/* Application styles. Every colour goes through a token in tokens.css — no hex, no rgb().
 * Brand assets come from evince-site and are never redrawn (see brand/wordmark.css).
 */
*{box-sizing:border-box}
  body{margin:0;background:var(--ev-cream);color:var(--ev-text-deep);font:16px/1.55 "Space Grotesk",system-ui,sans-serif}
  header{background:var(--ev-rust);color:var(--ev-sand);padding:18px 28px;display:flex;justify-content:space-between;align-items:center}
  header .logo{display:inline-flex;text-decoration:none}
  header nav a, header nav button{color:var(--ev-sand);background:none;border:0;font:inherit;cursor:pointer;margin-left:18px;text-decoration:none}
  /* ONE CONTAINER: 960px, centred, on every screen. Page frame 1280, gutter 60. Below ~1008 it
     goes fluid with a 24px gutter, and nothing rearranges into a different structure at any
     breakpoint — there is no wide variant and no narrow variant.

     THE CONTAINER IS CENTRED; THE CONTENT INSIDE IT IS LEFT-ALIGNED. Stepper, headline, lead and
     cards all share one left edge: the block is centred in the viewport, its contents are not
     centred within the block.

     THE READING MEASURE IS SEPARATE FROM THE CONTAINER, and that distinction is the whole point:
     a 700px PAGE leaves a laptop mostly empty and crushes anything with internal columns, while
     a 700px PARAGRAPH is simply readable. So the container is wide and the prose is capped at
     --ev-measure below. Constrain the text, not the page.

     box-sizing is border-box, so the cap carries its padding: the bare number would make the
     container 48px narrower than the width it is named after. */
  main{max-width:calc(var(--ev-container) + 2 * 24px);margin:48px auto;padding:0 24px;text-align:left}
  /* Long-form paragraphs only. A chip, a caption or a label is not long-form and keeps the full
     container; headings balance instead (text-wrap: balance) because they are short by design.
     `pretty` is what stops the last line being one orphaned word — "solutions", "today." — which
     is most of what reads as the text falling short of the box. */
  main p{max-width:var(--ev-measure);text-wrap:pretty}
  /* THE TEST IS THE COLUMN, NOT THE BOX. An earlier version of this rule said "a box that holds
     nothing but prose takes the measure", judging each box on its own. That is wrong, and it
     produced a contradiction on /work: by that test .wk-occ should narrow and .wk-block should
     not, which puts two stacked cards' right edges out of line — the exact fault we had just
     fixed. Boxes are not seen one at a time.

     So: a card that STACKS with other boxes in the column keeps the full width, always. A shared
     right edge down the page is worth more than the white space inside any one card, and the
     gutter left by the reading measure INSIDE a full-width card is correct, not a defect — the
     card is the unit of the grid, the paragraph is the unit of reading, and they are allowed to
     be different widths.

     .card--prose is only for a card ALONE on its page, where there is no column to break: the
     landing card, gap_none, courses_soon, confirmed. If a second box can ever render beside or
     above it, both take the same width or neither does. */
  /* A no-op, and now permanently so: the container IS the measure, so a card's content box is
     already 75 characters and there is nothing left to narrow. Every box on a page ends on the
     same edge as every other and as the text inside it. Kept defined so the markup carrying it
     does not have to change. */
  .card--prose{max-width:none}

  /* .ra is a vertical stack inside the container, with no width of its own — every screen is
     the same 1080. .qa keeps block layout so the questions page uses the margins it was written
     with rather than a 40px flex gap between every heading. */
  .ra { display: flex; flex-direction: column; gap: 40px; padding: 8px 0 24px; }
  .qa { display: block; }
  /* Admin pages: the profiles table needs the whole window. The column stays readable on the
     left — text blocks keep the 720px measure — and only .card--full takes the full width. */
  main.wide{max-width:none;margin:40px 0;padding:0 32px}
  main.wide > :not(.card--full):not(.tiles){max-width:720px}
  main.wide .card--full{max-width:none}
  main.wide .grid th,main.wide .grid td{padding-right:18px;white-space:nowrap}
  main.wide .grid td:first-child{white-space:normal;min-width:220px}
  .paging{display:flex;justify-content:space-between;gap:16px;margin:14px 0 0;font-size:var(--ev-size-small)}
  .paging a{color:var(--ev-rust)}
  .filter{display:flex;gap:12px;align-items:center;margin:0 0 22px;font-size:var(--ev-size-small);color:var(--ev-text-muted)}
  .filter label{color:var(--ev-text-deep);font-weight:500}
  /* The select is the app's own: sand rule, rust text, a chevron drawn with borders so it takes the token colour. */
  .select{position:relative;display:inline-block}
  .select select{appearance:none;-webkit-appearance:none;font:inherit;font-size:var(--ev-size-small);color:var(--ev-text-deep);padding:9px 38px 9px 14px;border:1.5px solid var(--ev-rule-link);border-radius:999px;background:var(--ev-surface-card);cursor:pointer;min-width:200px}
  .select select:hover{border-color:var(--ev-rust)}
  .select select:focus-visible{outline:2px solid var(--ev-focus-ring);outline-offset:2px}
  .select::after{content:"";position:absolute;right:16px;top:50%;width:7px;height:7px;border-right:1.5px solid var(--ev-rust);border-bottom:1.5px solid var(--ev-rust);transform:translateY(-70%) rotate(45deg);pointer-events:none}
  .filter a{color:var(--ev-rust)}
  .hist{display:inline-flex;align-items:flex-end;gap:2px;height:22px;width:64px}
  .hist i{flex:1;min-height:2px;background:var(--ev-teal);border-radius:2px 2px 0 0}
  .hist-lg{height:40px;width:120px;gap:4px}
  /* KPI tiles: a chart when the number is a share of something, the number alone when it is a count. */
  .tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:16px;margin:0 0 34px}
  .tile{background:var(--ev-surface-card);border:1px solid var(--ev-rule);border-radius:var(--ev-radius-card);padding:18px 20px;display:flex;gap:16px;align-items:center;box-shadow:var(--ev-shadow-card)}
  .tile > .donut{flex:0 0 84px}
  .tile-body{display:grid;gap:4px;min-width:0}
  .tile-k{font:400 36px/1 "Instrument Serif",serif;color:var(--ev-text-deep)}
  .tile-l{font-size:var(--ev-size-small);color:var(--ev-text-deep);font-weight:500}
  .tile-s{font-size:var(--ev-size-fine);color:var(--ev-text-muted);line-height:1.5}
  .tile-wide{grid-column:1 / -1;display:block}
  .eyebrow a{color:var(--ev-rust)}
  .tile-alert{border-color:var(--ev-accent)}
  .donut{width:84px;height:84px;transform:rotate(-90deg)}
  .donut .track{fill:none;stroke:var(--ev-rule-strong);stroke-width:3.2}
  .donut .value{fill:none;stroke:var(--ev-teal);stroke-width:3.2;stroke-linecap:round}
  .donut .value.miss{stroke:var(--ev-accent)}
  .donut .value.nobar{stroke:var(--ev-olive)}
  .donut .mark{stroke:var(--ev-rust);stroke-width:1.2}
  .stack{display:flex;height:22px;border-radius:6px;overflow:hidden;margin:8px 0 6px;background:var(--ev-rule)}
  .stack i{display:block;height:100%}
  .stack .a{background:var(--ev-teal)} .stack .p{background:var(--ev-clay)} .stack .r{background:var(--ev-rust)} .stack .u{background:var(--ev-rule-strong)}
  .legend{display:flex;flex-wrap:wrap;gap:6px 16px;font-size:var(--ev-size-fine);color:var(--ev-text-muted)}
  .funnel{display:grid;gap:6px;margin-top:10px}
  .funnel-step{display:grid;grid-template-columns:44px 1fr 150px;align-items:center;gap:12px;font-size:var(--ev-size-fine)}
  .funnel-n{font:400 20px/1 "Instrument Serif",serif;color:var(--ev-text-deep);text-align:right}
  .funnel-step i{display:block;height:14px;min-width:2px;background:var(--ev-teal);border-radius:3px}
  .funnel-l{color:var(--ev-text-muted)}
  .legend i{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:6px;vertical-align:-1px}
  .pill{display:inline-block;font:500 11px/1 "Space Grotesk",sans-serif;letter-spacing:.08em;text-transform:uppercase;padding:4px 8px;border-radius:999px;border:1px solid var(--ev-rule-link);color:var(--ev-text-muted);vertical-align:middle}
  .pill-ok{color:var(--ev-teal);border-color:var(--ev-teal)}
  .pill-miss{color:var(--ev-accent);border-color:var(--ev-accent)}
  .eyebrow{font-size:12px;letter-spacing:.2em;text-transform:uppercase;color:var(--ev-text-muted);margin:0 0 10px}
  h1{font:400 44px/1.1 "Instrument Serif",serif;margin:0 0 18px}
  h1 em{font-style:italic;color:var(--ev-accent)}
  h2{font:400 28px/1.2 "Instrument Serif",serif;margin:28px 0 10px}
  p.lead{font-size:18px;color:var(--ev-text-deep)}
    /* The system card: cream/white surface, radius 20, rust 14% edge, --ev-shadow-card. The
     shadow used to be a one-off 0 6px 24px of the RULE colour, which is a hairline value
     doing a shadow's job — same class of mistake as inventing a token. */
.card{background:var(--ev-on-accent);border:1px solid var(--ev-rule);border-radius:var(--ev-radius-card);padding:28px;box-shadow:var(--ev-shadow-card);margin:20px 0}
  /* Whose words are in this card. A grid of chips and a quoted question both read as ours until
     something says otherwise, and what the person is being asked to judge is their own CV. */
  .card__eyebrow{display:block;font-size:11px;letter-spacing:.16em;text-transform:uppercase;
    color:var(--ev-text-muted);margin:0 0 16px}
  label{display:block;font-weight:500;margin-bottom:6px}
  /* color, because a field with none falls to the browser's own near-black for form controls,
     and there is no black in this system. */
  input[type=email],input[type=file],textarea{width:100%;padding:12px 14px;border:1px solid var(--ev-rule-link);border-radius:12px;font:inherit;color:var(--ev-text-deep);background:var(--ev-on-accent)}
  textarea{min-height:170px;resize:vertical;line-height:1.55}
  textarea:focus,input:focus{outline:2px solid var(--ev-accent);outline-offset:1px}
  /* Stepper. The accent MARKS the active step; it does not fill it. White on terracotta measures
     3.74:1 and cream on terracotta 3.62:1, both short of AA 4.5:1 for text, so the label and the
     numeral stay deep rust at 6.99:1 on a 12% accent tint. A page-level rust fill was the other
     way to make it obvious, and it turns a progress indicator into a second header. */
  /* CENTRED on the card's content box below it, not flush to the container's left edge. The
     card is full width with symmetric 28px padding, so the content box's centre IS the
     container's centre and justify-content:center lands on it. This is the one element that
     centres: it spans the whole flow rather than belonging to the column of text, and it is
     how evince.app renders it. Everything else stays left-aligned on the shared edge. */
  .steps{display:flex;flex-wrap:nowrap;align-items:center;justify-content:center;gap:2px;margin:0 0 var(--ev-space-5);font-size:var(--ev-size-fine)}
  .step{display:inline-flex;align-items:center;gap:7px;padding:7px 11px;border-radius:var(--ev-radius-pill);text-decoration:none;border:1px solid transparent;white-space:nowrap}
  .step__dot{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;border:1px solid currentColor;font-size:11px;flex:0 0 auto}
  .step--todo{color:var(--ev-step-todo-fg)}
  .step--done{color:var(--ev-step-done-fg)}
  .step--current{background:var(--ev-step-active-tint);color:var(--ev-step-active-fg);border-color:var(--ev-step-active-mark);font-weight:500}
  .step--current .step__dot{border-color:var(--ev-step-active-mark);border-width:2px}
  a.step:hover{border-color:var(--ev-rule-link);color:var(--ev-rust)}
  a.step:focus-visible{outline:2px solid var(--ev-focus-ring);outline-offset:2px}
  .steps-compact{display:none;text-align:center;color:var(--ev-text-muted);font-size:var(--ev-size-fine);margin:0 0 var(--ev-space-4)}
  /* 720, not 640: measured, the six steps still fit at 768 and overflow by 641. */
  @media (max-width:720px){.steps{display:none}.steps-compact{display:block}}

  .flownav{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;margin:34px 0 0;padding-top:22px;border-top:1px solid var(--ev-rule)}
  .flownav .back{color:var(--ev-text-muted);text-decoration:none;padding:12px 0}
  .flownav .back:hover{color:var(--ev-rust)}
  .flownav form{text-align:right}
  .returnlink{display:flex;gap:8px;align-items:center;margin:10px 0 6px}
  .returnlink input{flex:1;min-width:0;font:inherit;font-size:var(--ev-size-small);padding:10px 12px;border:1px solid var(--ev-rule-link);border-radius:10px;background:var(--ev-surface-card);color:var(--ev-text-deep)}
  .cta-link{display:inline-block;background:var(--ev-cta-fill);color:var(--ev-on-cta);border-radius:999px;padding:12px 22px;text-decoration:none}
  .cta-link:hover{filter:brightness(.95)}
  @media (max-width:600px){.steps{font-size:12px}.step{padding:6px 10px}}
  .claim{background:var(--ev-on-accent);border:1px solid var(--ev-rule);border-radius:20px;padding:22px 24px;box-shadow:0 6px 24px var(--ev-rule);margin:16px 0}
  .claim.settled{box-shadow:none;background:var(--ev-surface-settled)}
  .claim.gone{padding:14px 22px;background:transparent;border-style:dashed;box-shadow:none}
  .claim-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:10px;justify-content:space-between}
  .claim h2{font:400 25px/1.25 "Instrument Serif",serif;margin:0}
  .band{font-size:11px;letter-spacing:.14em;text-transform:uppercase;padding:4px 11px;border-radius:999px;white-space:nowrap}
  .band-demonstrated{background:var(--ev-teal);color:var(--ev-on-accent)}
  .band-supported{background:var(--ev-sand);color:var(--ev-rust)}
  .band-mentioned{background:transparent;color:var(--ev-text-muted);border:1px solid var(--ev-rule-link)}
  .claim .esco{font-size:13px;color:var(--ev-text-muted);margin:6px 0 0}
  .claim .why{margin:12px 0 0}
  .claim .struck{text-decoration:line-through;text-decoration-thickness:1px}
  .claim .removed-note{color:var(--ev-text-muted);font-size:14px;margin:4px 0 0}
  .undo{background:none;border:0;color:var(--ev-rust);font:inherit;font-size:14px;text-decoration:underline;cursor:pointer;padding:6px 2px;margin-left:6px}
  .claim .removed,.claim .settled-note{color:var(--ev-text-muted);margin:0;font-size:15px}
  .claim .tick{color:var(--ev-teal)}
  .claim .ev{margin-top:14px}
  .claim .ev summary{cursor:pointer;color:var(--ev-text-muted);font-size:14px}
  .claim .ev ul{margin:10px 0 0;padding-left:18px}
  .claim .ev li{margin-bottom:9px;font-size:15px}
  .claim .ev .kind{font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--ev-text-muted);margin-right:6px}
  /* The "Partly" note. Same treatment as the questions screen's answer box — cream ground, rust
     hairline, radius 12 — because it is the same act: the person writing something in their own
     words. What differs is the height at rest. */
  .claim .note{margin-top:12px;display:flex;flex-direction:column;gap:8px}
  .claim .note label{font-size:14px;color:var(--ev-text-muted)}
  /* min-height:0 undoes the 170px that the global textarea rule gives an answer box: here that
     would be a block of empty cream under an optional question. It starts at one row and grows on
     input, and max-height stops it at about six rows, after which it scrolls rather than pushing
     the verdict buttons off the screen. */
  .note__field{min-height:0;max-height:11rem;padding:12px 16px;font-size:16px;line-height:1.6;
    background:var(--ev-cream);overflow-y:auto}
  .note__help{margin:0;color:var(--ev-text-muted);font-size:13px}
  .verdicts{display:flex;flex-wrap:wrap;gap:10px;margin-top:18px}
  .verdicts form{margin:0}
  .verdict{min-height:48px;padding:12px 20px;border-radius:999px;border:1.5px solid var(--ev-rule-link);background:var(--ev-on-accent);font:inherit;color:var(--ev-text-deep);cursor:pointer}
  .verdict:hover{border-color:var(--ev-rust)}
  /* No verdict button is styled as the primary one. Filling "Yes, that's me" made it read as
     already chosen AND as the recommended answer, on a question about the person's own skills whose
     answers feed the spec §4 acceptance rate. All three carry equal weight until one is chosen. */
  .verdict:hover{border-color:var(--ev-rust);color:var(--ev-rust)}
  .verdict:focus-visible{outline:2px solid var(--ev-accent);outline-offset:2px}
  @media (max-width:600px){.verdicts{flex-direction:column}.verdict{width:100%}.claim h2{font-size:22px}}
  .gap{margin:16px 0 0;padding:14px 16px;background:var(--ev-tint-sand);border-radius:14px}
  .pay{margin:10px 0 0;color:var(--ev-text-muted);font-size:var(--ev-size-small)}
  .gap h3{font:500 13px/1 "Space Grotesk",sans-serif;letter-spacing:.1em;text-transform:uppercase;color:var(--ev-rust);margin:0 0 8px}
  .gap ul{margin:8px 0 0;padding-left:18px}
  /* Stage list. No bar and no clock: both were estimates dressed as measurements. These five are
     real state, written by the job as it reaches each one. */
  /* The labels align to the CARD'S CONTENT EDGE, not to the glyph column. The list is pulled left
     by exactly the card's padding and the marks hang in that gutter, so every line of text in the
     card — the count, the labels, the promise — starts on one edge. 18 + 10 = 28 = the padding;
     change one of the three and change all three. */
  .stages{list-style:none;margin:0 0 0 -28px;padding:0}
  .stage{display:flex;align-items:center;gap:10px;padding:var(--ev-space-2) 0;font-size:var(--ev-size-body)}
  .stage__mark{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;flex:0 0 auto}
  .stage--todo{color:var(--ev-step-todo-fg)}
  /* Without this the glyph column stops after the active row and the list reads as broken
     rather than as four items with two still to come. */
  .stage--todo .stage__mark::before{content:"";width:9px;height:9px;border-radius:50%;
    border:1.5px solid var(--ev-rule-link);box-sizing:border-box}
  .stage--done,.stage--active,.stage--failed{color:var(--ev-text-deep)}
  .stage--done .stage__mark{color:var(--ev-step-done-fg)}
  .stage--failed .stage__mark{color:var(--ev-text-deep);font-size:19px}
  /* The count of what has been found, above the stages. The figure carries the display face
     because it is the one thing on this screen that is about the person rather than about us. */
  .stage-found{margin:0 0 18px;padding-bottom:16px;border-bottom:1px solid var(--ev-rule);
    color:var(--ev-text-deep);font-size:var(--ev-size-body)}
  .stage-found strong{font-family:var(--ev-font-display);font-weight:400;font-size:34px;
    line-height:1;margin-right:8px;vertical-align:-3px}
  /* Shown from 20s. The gap between "running" and "failed" is where a wait feels broken. */
  .stage-slow{margin:10px 0 0;color:var(--ev-text-muted);font-size:13px}
  .sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
    clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
  .stage-error{color:var(--ev-text-deep);margin:var(--ev-space-4) 0 0}
  /* The one moving thing on the page: the wordmark's C, one turn every eight seconds. */
  .stage__spin{width:16px;height:16px;overflow:visible;color:var(--ev-accent);animation:ev-turn 8s linear infinite}
  .stage__spin ellipse{fill:none;stroke:currentColor;stroke-width:7}
  @keyframes ev-turn{to{transform:rotate(360deg)}}
  /* Short waits (a form marked data-wait): the phrase centred over the page behind a scrim, with the
     same turning C. Without these rules the box is an ordinary block at the foot of the page. */
  #waiting{position:fixed;inset:0;background:var(--ev-scrim);display:none;align-items:center;justify-content:center;z-index:50}
  #waiting.on{display:flex}
  #waiting .box{max-width:420px;padding:0 28px;text-align:center}
  #waiting .stage__spin{display:block;width:34px;height:34px;margin:0 auto 14px}
  #waiting p{margin:0}
  @media (prefers-reduced-motion:reduce){
    .stage__spin{animation:none}
    .stage__spin ellipse{display:none}
    #waiting .stage__spin ellipse{display:initial}
    .stage--active .stage__mark::before{content:"";width:9px;height:9px;border-radius:50%;background:var(--ev-accent)}
  }
  /* What the person has already answered, readable and correctable. */
  .answered{list-style:none;margin:0 0 var(--ev-space-5);padding:0}
  .answered__item{border-top:1px solid var(--ev-rule);padding:var(--ev-space-4) 0}
  .answered__q{margin:0;color:var(--ev-text-muted);font-size:var(--ev-size-small)}
  .answered__a{margin:6px 0 0;color:var(--ev-text-deep)}
  .answered__a--none{color:var(--ev-text-muted);font-style:italic}
  .answered__item .undo{display:inline-block;margin:6px 0 0;padding-left:0}
  .struck{text-decoration:line-through;text-decoration-thickness:1px}
  .removed-note{color:var(--ev-text-muted);font-size:var(--ev-size-small);margin:4px 0 0}
  .undo{background:none;border:0;color:var(--ev-rust);font:inherit;font-size:var(--ev-size-small);text-decoration:underline;cursor:pointer;padding:6px 2px;margin-left:6px}
  .gap{margin:16px 0 0;padding:14px 16px;background:var(--ev-tint-sand);border-radius:14px}
  .gap h3{font:500 13px/1 var(--ev-font-ui);letter-spacing:var(--ev-tracking-eyebrow);text-transform:uppercase;color:var(--ev-rust);margin:0 0 8px}
  .gap ul{margin:8px 0 0;padding-left:18px}
  .gap-list{list-style:none;margin:0;padding:0}
  .gap-list li{padding:10px 0;border-bottom:1px solid var(--ev-rule);display:flex;flex-wrap:wrap;gap:8px;align-items:baseline}
  .gap-list li:last-child{border-bottom:0}
  .pick{margin:16px 0 0}
  /* What this role is. The first thing on a card a person has never heard of. */
  .whatis{margin:14px 0 18px;padding:0 0 0 14px;border-left:2px solid var(--ev-rule)}
  .whatis h3{font:500 13px/1 var(--ev-font-ui);letter-spacing:var(--ev-tracking-eyebrow);
             text-transform:uppercase;color:var(--ev-rust);margin:0 0 8px}
  .whatis p{margin:0 0 8px}
  .whatis p:last-child{margin:0}
  .whatis .source{font:400 13px/1.5 var(--ev-font-ui);letter-spacing:.02em;margin-top:10px}
  .whatis .source a{color:var(--ev-role-source-fg);text-underline-offset:3px}
  .carries em{font-style:normal;font-weight:600;color:var(--ev-text-deep)}
  /* The confirmed skills, before the roles are built from them. Two columns when there is room. */
  .confirmed{margin:8px 0 0;padding-left:18px}
  .confirmed li{padding:3px 0;break-inside:avoid}
  /* Two columns only when there are enough to fill both; three items would leave one alone. */
  .confirmed--two{columns:2;column-gap:28px}
  @media (max-width:600px){.confirmed--two{columns:1}}
  /* What the role builds on. Open, not a disclosure: it is the card's evidence, not its footnote. */
  .builds{margin:16px 0 0;padding:14px 16px;background:var(--ev-tint-sand);border-radius:14px}
  .builds h3{font:500 13px/1 var(--ev-font-ui);letter-spacing:var(--ev-tracking-eyebrow);
             text-transform:uppercase;color:var(--ev-rust);margin:0 0 8px}
  .builds ul{margin:8px 0 0;padding-left:18px}
  .builds li{padding:2px 0}
  /* The second action on a card. One CTA per page: it belongs to the picked role. */
  .quiet{background:none;border:0;color:var(--ev-rust);font:inherit;text-decoration:underline;
         text-underline-offset:3px;cursor:pointer;padding:6px 0}
  .quiet:hover{color:var(--ev-text-deep)}
  .quiet:focus-visible{outline:2px solid var(--ev-focus-ring);outline-offset:2px}
  /* The rest of the gap. Closed by default: three things to start on is a plan, twenty is a list. */
  .more{margin:10px 0 0}
  .more summary{cursor:pointer;color:var(--ev-rust);font-size:var(--ev-size-small);padding:8px 0;list-style:none}
  .more summary::-webkit-details-marker{display:none}
  .more summary::before{content:"+ ";font-variant-numeric:tabular-nums}
  .more[open] summary::before{content:"− "}
  .more summary:focus-visible{outline:2px solid var(--ev-focus-ring);outline-offset:2px}
  .more .gap-list{border-top:1px solid var(--ev-rule)}
  .verdict:hover{border-color:var(--ev-rust);color:var(--ev-rust)}
  .verdict:focus-visible{outline:2px solid var(--ev-focus-ring);outline-offset:2px}

  .chips{display:flex;flex-wrap:wrap;gap:10px;margin:6px 0 4px}
  .chip{display:inline-flex;align-items:center;gap:8px;min-height:48px;padding:11px 18px;border:1.5px solid var(--ev-rule-link);border-radius:999px;background:var(--ev-on-accent);font:inherit;color:var(--ev-text-deep);cursor:pointer;-webkit-tap-highlight-color:transparent}
  .chip[aria-pressed=true]{background:var(--ev-rust);border-color:var(--ev-rust);color:var(--ev-on-accent)}
  /* ONE COUNTER. The label belongs to the bar, so the two are one group with one margin under
     them, and .progress carries none of its own. */
  .qcount{display:flex;flex-direction:column;gap:10px;margin:0 0 28px}
  .qcount__row{display:flex;justify-content:space-between;align-items:baseline;
    font-size:12px;letter-spacing:.2em;text-transform:uppercase;color:var(--ev-text-muted)}
  .progress{display:flex;gap:6px;margin:0}
  .progress i{flex:1;height:4px;border-radius:2px;background:var(--ev-rule-strong)}
  .progress i.on{background:var(--ev-accent)}
  .skip{background:none;border:0;color:var(--ev-text-muted);font:inherit;text-decoration:underline;cursor:pointer;padding:12px 0}
  /* Skip and Next as one group on the right of the action row, Next furthest right. */
  .flownav__go{display:inline-flex;align-items:center;gap:24px}
  @media (max-width:600px){main{margin:24px auto}h1{font-size:34px}.chip{min-height:52px}}
  blockquote.q{font:400 26px/1.3 "Instrument Serif",serif;margin:0 0 8px;border-left:4px solid var(--ev-accent);padding-left:18px}
  button.cta{background:var(--ev-cta-fill);color:var(--ev-on-cta);border:0;border-radius:999px;padding:12px 22px;font:500 16px "Space Grotesk",sans-serif;cursor:pointer;margin-top:14px}
  button.cta:hover{filter:brightness(.95)}
  button.danger{background:none;color:var(--ev-rust);border:1px solid var(--ev-rust);border-radius:999px;padding:10px 18px;font:inherit;cursor:pointer}
  .muted{color:var(--ev-text-muted);font-size:14px}
  .ok{border-left:4px solid var(--ev-teal);padding-left:14px}
  .err{border-left:4px solid var(--ev-accent);padding-left:14px;color:var(--ev-rust)}
  /* The same container as main. At 720 the footer's left edge sat 120px right of everything
     above it, which is the one left edge the layout is built on. */
  footer{max-width:calc(var(--ev-container) + 2 * 24px);margin:60px auto;padding:0 24px;color:var(--ev-text-muted);font-size:13px}
  footer p{margin:0 0 6px}
  footer a{color:inherit}
  .card a{color:var(--ev-rust)}
  .grid{width:100%;border-collapse:collapse;font-size:var(--ev-size-small)}
  .grid th{text-align:left;font-weight:500;color:var(--ev-text-muted);padding:6px 8px 6px 0;border-bottom:1px solid var(--ev-rule)}
  .grid td{padding:7px 8px 7px 0;border-bottom:1px solid var(--ev-rule);vertical-align:top}

  /* --- the questions transcript ----------------------------------------------------------------- */
  /* A disclosure under the actions. It was drawn as a right rail, which a 700px column has no room
     for — and a list of everything already answered, placed above the one question still open, was
     the wrong order for a screen whose job is the next question. The count rides on the summary so
     nobody has to open it to learn whether there is anything inside. */
  .said{margin-top:28px;border-top:1px solid var(--ev-rule);padding-top:14px}
  .said summary{font:400 15px/1.5 var(--ev-font-ui);color:var(--ev-text-muted);cursor:pointer}
  /* Opened, it is a panel and not a run of text against the page: the answers are a record being
     consulted, which is a different thing from the question being asked above them. */
  .said__panel{background:var(--ev-tint-sand);border-radius:20px;padding:22px 24px;margin-top:12px}
  .said .answered{margin:0}
  .said .answered__item:first-child{border-top:0;padding-top:0}
  /* max-width:none because the rule above it is the panel's, not the sentence's: main p caps
     paragraphs at --ev-measure, which left the hairline stopping two thirds of the way across. */
  .said__note{margin:0;padding-top:18px;border-top:1px solid var(--ev-rule);max-width:none;
    color:var(--ev-text-muted);font-size:13px;line-height:1.6}

  /* ------------------------------------------------------------------ screen 1, /start
     The invitation, the file, the terms, then the one action. Consent used to be a screen of its
     own with a single button on it, which asked someone to weigh terms against nothing. */
  .st__head{display:flex;flex-direction:column;gap:14px}
  .st__head h1{margin:0}
  .st__head .eyebrow{margin:0}
  .st__head .lead{margin:0}

  /* EMPTY. Dashed, because nothing is in it yet — the border says "put something here" in a way
     a solid card does not. The file input stays a visible, plain input rather than a label
     dressed as a button: this is the front door, and a phone that cannot get past it cannot use
     the product at all. */
  .st-drop{display:flex;flex-direction:column;align-items:center;gap:14px;
    border:1px dashed var(--ev-rule-link);border-radius:20px;padding:40px 28px;
    background:var(--ev-on-accent);text-align:center}
  .st-drop__mark{display:inline-block;width:22px;height:22px;border:2px solid var(--ev-text-muted);
    border-right-color:transparent;border-radius:50%;transform:rotate(-42deg)}
  .st-drop label{font-size:17px;color:var(--ev-text-deep)}
  .st-drop__note{margin:0;font-size:13px;color:var(--ev-text-muted)}
  .st-drop input[type=file]{max-width:100%}
  /* Disabled until the terms are ticked, so the order on the page is the order of events. */
  .st-drop input[type=file]:disabled{opacity:.45;cursor:not-allowed}

  /* READY. The file that was stored, what it is, and the way back out of it. */
  .st-file{display:flex;align-items:center;gap:14px;
    border:1px solid var(--ev-rule-strong);border-radius:20px;padding:22px 26px;
    background:var(--ev-on-accent);box-shadow:0 6px 24px var(--ev-rule)}
  .st-file__mark{display:inline-block;width:18px;height:18px;border:2px solid var(--ev-teal);
    border-right-color:transparent;border-radius:50%;transform:rotate(-42deg);flex-shrink:0}
  .st-file__what{display:flex;flex-direction:column;gap:3px;flex:1}
  .st-file__name{font-weight:700;color:var(--ev-text-deep)}
  .st-file__meta{font-size:13px;color:var(--ev-text-muted)}
  .st-file__swap{font-size:14px;color:var(--ev-text-muted)}

  /* THE TERMS, next to the thing they are about. CONSENT_TEXT renders verbatim. */
  .st-terms{background:var(--ev-tint-sand);border-radius:20px;padding:26px 28px;margin-top:20px;
    display:flex;flex-direction:column;gap:16px}
  .st-terms__text{margin:0;font-size:15px;line-height:1.65;color:var(--ev-text-deep)}
  .st-terms__meta{margin:0;font:400 12px/1.5 var(--ev-font-source);color:var(--ev-text-muted);max-width:none}
  .st-terms__rule{height:1px;background:var(--ev-rule)}
  /* A deliberate tick, never an implied "by continuing you agree". */
  .st-tick{display:flex;align-items:flex-start;gap:12px;cursor:pointer}
  .st-tick input{width:20px;height:20px;margin:2px 0 0;flex-shrink:0;accent-color:var(--ev-rust)}
  .st-tick span{font-size:16px;line-height:1.5;color:var(--ev-text-deep)}
  /* Off WITH A REASON beside it, rather than silently dead. */
  .cta:disabled{opacity:.4;cursor:not-allowed;box-shadow:none}

  /* ------------------------------------------------------------------ screen 3, /cv
     The payoff of act one. The paragraph is the screen, so it is set larger than body copy and
     kept to the reading measure; everything else on the page is support for it. */
  .cv__head{display:flex;flex-direction:column;gap:20px}
  .cv__head h1{margin:0}
  .cv__head .eyebrow{margin:0}
  .cv__para{margin:0;font-size:22px;line-height:1.6;color:var(--ev-text-deep);max-width:var(--ev-measure);text-wrap:pretty}
  .cv-read{background:var(--ev-tint-sand);border-radius:20px;padding:24px 26px;
    display:flex;flex-direction:column;gap:14px}
  .cv-read__list{display:flex;flex-direction:column;gap:10px}
  .cv-read__item{display:flex;gap:10px;align-items:flex-start;font-size:15px;line-height:1.6;
    color:var(--ev-text-deep)}

/* The brand's own glyph: an open ellipse rotated -42deg, the same mark as the wordmark's C. */
.wk-glyph {
  display: inline-block; width: 11px; height: 11px;
  border: 1.5px solid var(--ev-rust); border-right-color: transparent;
  border-radius: 50%; transform: rotate(-42deg);
}
.wk-glyph--sm {
  width: 9px; height: 9px; border-color: var(--ev-rust); border-right-color: transparent;
  flex-shrink: 0; margin-top: 6px;
}


/* The two groups STACK, one above the other. They are one reading order, not a comparison, and a
   column each made the shorter one look like a failed half of a pair. */

  /* The skills the CV never claimed lead /story, under their own heading. They are the reason the
     page exists: a skill someone already wrote down is one they already knew they had. */
  .story-group{font:400 30px/1.2 "Instrument Serif",serif;margin:8px 0 18px;color:var(--ev-text-deep)}
  .story-group em{font-style:italic;color:var(--ev-accent)}
  .story-divider{height:1px;background:var(--ev-rule);margin:34px 0 30px}
  /* What was chosen, before anything is sent. The file is read into memory here and goes nowhere
     until the one action is pressed. */
  .st-drop__picked{margin:0;font-weight:700;color:var(--ev-text-deep)}

  /* ------------------------------------------------------- the handover, and the ground it needs
     Ported from @evince/ui (Handover, Panel). _ds_bundle.js needs React on the page and
     this app is Jinja + HTMX with no build step, so the components are carried over as markup and
     CSS. The GEOMETRY and the KEYFRAMES are the library's, character for character; the class
     names are kept so the lineage is readable from the markup.

     One thing could not be carried as a token: the library animates at a literal `5s`, and the
     motion scale stops at --ev-dur-entrance (900ms). There is no token of that magnitude to use
     and inventing one is how --ev-ruler-here-mark got into tokens.css. The literal matches
     upstream exactly; if the system later names it, this is the line to change. */
  .ev-handover{display:block;width:100%;max-width:300px;height:auto;color:var(--ev-sand);
    margin:0 auto var(--ev-space-5)}
  /* The gesture takes the colour of the GROUND it is on — tone names the ground, not the ink.
     It was written for rust and drew in sand, which made it invisible on this app's cream. */
  .ev-surface--cream .ev-handover,
  .ev-surface--sand .ev-handover{color:var(--ev-rust)}
  .ev-handover--rust{color:var(--ev-sand)}
  .ev-handover--cream,
  .ev-handover--sand{color:var(--ev-rust)}
  .ev-handover__circle{fill:none;stroke:currentColor;stroke-width:5}
  .ev-handover__circle--leave{animation:ev-hand-l 5s var(--ev-ease) infinite}
  .ev-handover__circle--enter{animation:ev-hand-r 5s var(--ev-ease) infinite}

  @keyframes ev-hand-l{
    0%{stroke-dasharray:0 100;opacity:0}
    4%{opacity:1}
    28%{stroke-dasharray:75 25;opacity:1}
    42%{stroke-dasharray:75 25;opacity:.55}
    88%{stroke-dasharray:75 25;opacity:.55}
    96%,100%{stroke-dasharray:75 25;opacity:0}
  }
  @keyframes ev-hand-r{
    0%,34%{stroke-dasharray:0 100;opacity:0}
    38%{opacity:1}
    62%{stroke-dasharray:75 25;opacity:1}
    88%{stroke-dasharray:75 25;opacity:1}
    96%,100%{stroke-dasharray:75 25;opacity:0}
  }
  /* A REAL RESTING STATE, and the one place this departs from the library. Its global reduced-
     motion rule collapses every animation to 0.01ms with one iteration, which lands both circles
     on their LAST keyframe — and both end at opacity 0. The gesture disappears entirely.
     What it settles to is not a guess: it is the Mark, which the system describes as "two open
     circles linked at their openings — the career you leave at 55% strength opening into the one
     you enter at full strength". Those are the 42-88% and 62-88% values of these same keyframes. */
  @media (prefers-reduced-motion:reduce){
    .ev-handover__circle{animation:none;stroke-dasharray:75 25}
    .ev-handover__circle--leave{opacity:.55}
    .ev-handover__circle--enter{opacity:1}
  }

  /* The library's Panel, ported faithfully and kept for when the app moves to it. It is NOT used
     on the wait screen: every other box in this app is a .card, so one square hairline panel among
     them reads as a broken box, not as the system's default enclosure. Moving the whole app from
     Card to Panel is its own decision. */
  .ev-panel{display:flex;flex-direction:column;gap:var(--ev-space-4);
    border:1px solid var(--ev-rule);padding:var(--ev-space-6)}
  /* The wait card is the same box as the rest of the app: full column width, left edge shared with
     the headline above it. NOT centred — the container is centred, its contents are not. With the
     gesture carrying the screen the card no longer has to hold the eye, so it does not need to be
     narrowed to hide how little is in it. */
  .card--wait{display:flex;flex-direction:column;gap:var(--ev-space-4)}
  /* The stages recede under the gesture: they are a list of what is happening, not the finding. */
