/* =========================================================================
   Cammino design system

   This replaces the old stylesheet rather than layering over it. The previous
   attempt kept app/styles.css and painted new colours on top, which is why
   the interface still looked like the old one wearing a coat: the components
   were unchanged, only their fill was.

   WHAT CHANGED, CONCRETELY

   - One card recipe with real presence (generous radius, hairline border,
     two-part shadow) instead of bordered boxes.
   - A widget: label row, body, optional action. Every panel in the app is one
     of these, so the app reads as one system rather than a pile of sections.
   - Interface type is the sans at heavy weights and tight tracking. The serif
     is reserved for the public site's statements, where a voice is wanted.
     An app should feel operated, not read.
   - Navigation that is a real object: a floating bar, not a strip of links.
   - Empty states are a designed component, because a product built on
     progressive personalisation shows more empty states than full ones early
     on, and they carry the promise.

   THEMES

   Both, always, and the person chooses. `data-theme` on <html> is "light",
   "dark", or absent — absent means follow the operating system. Every colour
   below is a token defined in all three states, so no component ever needs to
   know which theme is running.
   ========================================================================= */

/* =========================================================================
   TYPE

   These files are ours, in web/assets/fonts, built by tools/build_fonts.py.
   They used to come from fonts.googleapis.com, which cost 219 KB on the
   landing page — more than all eight photographs together — plus two fresh
   connections to servers we do not control, opened before the browser could
   draw a single letter. Self-hosted and cut down to what these pages use, the
   same three faces are 59 KB, on a connection that is already open.

   font-display:swap means text is readable in Georgia or the system sans from
   the first paint and re-sets when the real face lands. The alternative is a
   page of correct, invisible words.

   The weight ranges are not decoration. These are variable fonts: one file
   covers a span of weights and the browser interpolates inside it. Ask for a
   weight outside the declared range and it is silently clamped to the nearest
   end — 800 would come out at 700. If you write a rule needing a weight
   outside these ranges, rebuild the fonts; do not just write the rule.
   ========================================================================= */

@font-face{
  font-family:'Plus Jakarta Sans';
  src:url('assets/fonts/jakarta.woff2') format('woff2');
  font-weight:400 700;   /* 400 body, 500 quiet labels, 600 UI, 700 headings */
  font-style:normal;
  font-display:swap;
}

@font-face{
  font-family:'Newsreader';
  src:url('assets/fonts/newsreader.woff2') format('woff2');
  font-weight:300 400;   /* 300 the landing headline, 400 the wordmark */
  font-style:normal;
  font-display:swap;
}

/* Latin letters only — 8.6 KB rather than 21. It sets one emphasised word in
   the landing headline and nothing else on either page. Because that word is
   written into index.html rather than coming from anybody's data, the cut is
   safe; web/tests/fonts.test.js reads that headline and fails if it ever
   gains a character this file cannot draw. */
@font-face{
  font-family:'Newsreader';
  src:url('assets/fonts/newsreader-italic.woff2') format('woff2');
  font-weight:300;
  font-style:italic;
  font-display:swap;
}

/* ------------------------------------------------------------- tokens */

:root{
  /* Light. Cool off-white ground carrying a trace of the brand blue, so navy
     sits IN the page rather than on it. Not warm cream; not pure white. */
  --ground:#F4F7FB;
  --surface:#FFFFFF;
  --raised:#FFFFFF;
  --sunk:#EDF2F8;

  /* Three text weights, not four. A fourth tier lighter than --muted cannot
     reach 4.5:1 against this ground no matter how it is mixed, so it does not
     exist. There used to be a --faint; it measured 2.53:1 and was being used
     for placeholders and reason codes. See web/tests/contrast.test.js. */
  --ink:#0F1B26;
  --ink-2:#3D4F60;
  --muted:#5D7082;

  /* Decorative separators. These carry no meaning on their own, so they are
     allowed to be quiet. */
  --line:#E2EAF2;
  --line-2:#D3DEE9;
  /* The boundary of a control that has no fill of its own — a text input, a
     choice button. WCAG 1.4.11 asks 3:1 for these, and is right to: an input
     whose edge you cannot see is an input you do not know is there. */
  --field-line:#828D98;

  --brand:#0D2B45;
  --brand-ink:#FFFFFF;
  --accent:#2F6FB0;
  --accent-quiet:#E8F0F9;

  --good:#2C6E49; --good-bg:#E6F2EB;
  --warn:#96601C; --warn-bg:#FAF0E0;
  --crit:#9B3B28; --crit-bg:#F9EAE6;

  --r-sm:10px; --r:16px; --r-lg:22px; --r-xl:28px; --r-pill:999px;

  --lift:0 1px 2px rgba(15,27,38,.05), 0 10px 26px -14px rgba(15,27,38,.18);
  --lift-2:0 2px 4px rgba(15,27,38,.06), 0 22px 44px -22px rgba(15,27,38,.26);

  --sans:'Plus Jakarta Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --serif:'Newsreader',Georgia,serif;
  /* No webfont here on purpose. This stack used to lead with 'IBM Plex Mono',
     which was never loaded by either page — so almost every visitor already
     got the system monospace, and the handful with Plex installed locally saw
     a different product. The system faces (SF Mono, Cascadia Mono, Roboto
     Mono) all have tabular figures, which is the only property the readouts
     actually need, and they cost nothing to download. */
  --mono:ui-monospace,SFMono-Regular,'Cascadia Mono',Menlo,Consolas,monospace;

  --nav-h:64px;
}

/* Dark, for viewers whose system prefers it and who have not chosen. */
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --ground:#08121B;
    --surface:#0F1D28;
    --raised:#152736;
    --sunk:#0C1922;

    --ink:#EAF1F8;
    --ink-2:#BACADA;
    --muted:#8DA2B6;

    --line:#1D2F3E;
    --line-2:#283D4F;
    --field-line:#54697B;

    --brand:#E9F1F9;
    --brand-ink:#0B1620;
    --accent:#6FA8DC;
    --accent-quiet:#132534;

    --good:#7FC79B; --good-bg:#11241B;
    --warn:#DCAE68; --warn-bg:#241D12;
    --crit:#E08E7A; --crit-bg:#251512;

    --lift:0 1px 2px rgba(0,0,0,.4), 0 10px 26px -14px rgba(0,0,0,.7);
    --lift-2:0 2px 6px rgba(0,0,0,.45), 0 24px 48px -24px rgba(0,0,0,.8);
  }
}

/* Dark, chosen explicitly. Wins over a light operating system. */
:root[data-theme="dark"]{
  --ground:#08121B;
  --surface:#0F1D28;
  --raised:#152736;
  --sunk:#0C1922;

  --ink:#EAF1F8;
  --ink-2:#BACADA;
  --muted:#8DA2B6;

  --line:#1D2F3E;
  --line-2:#283D4F;
  --field-line:#54697B;

  --brand:#E9F1F9;
  --brand-ink:#0B1620;
  --accent:#6FA8DC;
  --accent-quiet:#132534;

  --good:#7FC79B; --good-bg:#11241B;
  --warn:#DCAE68; --warn-bg:#241D12;
  --crit:#E08E7A; --crit-bg:#251512;

  --lift:0 1px 2px rgba(0,0,0,.4), 0 10px 26px -14px rgba(0,0,0,.7);
  --lift-2:0 2px 6px rgba(0,0,0,.45), 0 24px 48px -24px rgba(0,0,0,.8);
}

/* ------------------------------------------------------------- base */

*{margin:0;padding:0;box-sizing:border-box}

/* The `hidden` attribute must actually hide things.
   ---------------------------------------------------------------------------
   Browsers implement it as `[hidden]{display:none}` in their own stylesheet, at
   the lowest possible specificity — so ANY class here that sets `display` beats
   it. `.c-tabs{display:flex}` did, and the bottom tab bar was therefore on
   screen for signed-out visitors, offering Home, Journey and Jobs to somebody
   with no account. Nobody noticed, because every screenshot anyone took was of
   a signed-in session.

   That is not a bug in the tab bar. It is a bug that was waiting in every
   component with a display rule and a `hidden` state, which is most of them,
   and it will not announce itself in any of the others either.

   `!important` is the right tool exactly once, and this is the occasion:
   `hidden` means "not relevant to this page right now", and nothing about a
   component's own layout should be able to argue with that. Both browser
   drives assert that nothing carrying the attribute is on screen. */
[hidden]{display:none !important}
html{
  -webkit-text-size-adjust:100%; scroll-behavior:smooth;
  /* On the root as well as on body. `clip` is not inherited by the scrolling
     box, and the document — not body — is what actually scrolls, so clipping
     only body left the page still able to rock a few pixels sideways on a
     phone. `clip` rather than `hidden` so nothing becomes a scroll container
     and breaks position:sticky. */
  overflow-x:clip;
}
@media (prefers-reduced-motion:reduce){ html{scroll-behavior:auto} }

body{
  font-family:var(--sans);
  font-size:16px; line-height:1.6;
  color:var(--ink); background:var(--ground);
  -webkit-font-smoothing:antialiased;
  min-height:100svh;
  /* `clip`, not `hidden`. Both stop the page rocking sideways on a phone —
     the reveal animations transform elements a few pixels past the right edge
     while they are in flight, which on a 390px screen is a visible twitch —
     but `hidden` would make body a scroll container and quietly break every
     position:sticky inside it. `clip` does not. */
  overflow-x:clip;
}

h1,h2,h3,h4{
  font-family:var(--sans);
  font-weight:700; letter-spacing:-.022em; line-height:1.18;
  color:var(--ink); text-wrap:balance;
}
h1{font-size:clamp(1.9rem,4.4vw,2.6rem); letter-spacing:-.03em}
h2{font-size:clamp(1.35rem,2.6vw,1.75rem)}
h3{font-size:1.06rem; letter-spacing:-.012em}
h4{font-size:.94rem}
p{color:var(--ink-2)}
a{color:var(--accent); text-decoration:none}
a:hover{text-decoration:underline}
button{font-family:inherit}
/* Two rings, not one. The accent alone measures 2.78:1 against the navy
   primary button, which means a keyboard user tabbing onto the most important
   control on the page could barely tell they had landed on it. The inner ring
   is --surface, which is always the opposite lightness to --brand in both
   themes, so whichever background the focused thing sits on, one of the two
   rings is clearly visible. */
:focus-visible{
  outline:2px solid var(--accent);
  outline-offset:2px;
  box-shadow:0 0 0 2px var(--surface);
  border-radius:6px;
}

.c-wrap{max-width:64rem; margin:0 auto; padding:0 clamp(1rem,4vw,2rem)}
.c-wrap--narrow{max-width:44rem}
.c-muted{color:var(--muted)}
.c-small{font-size:.86rem}
.c-mono{font-family:var(--mono); font-variant-numeric:tabular-nums}

/* ------------------------------------------------------- assistive tech */

/* Present to a screen reader, absent to everyone else. Not display:none,
   which would hide it from both. Used for the live region that announces a
   screen change, and for headings that name a region the eye reads from
   layout. */
.c-sr{
  position:absolute; width:1px; height:1px; padding:0; margin:0;
  overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0;
}

/* The first thing in the tab order, invisible until it has focus. Without it
   every keyboard visit to the app starts by tabbing past nine navigation
   items to reach the thing they came for. */
.c-skip{
  position:absolute; left:1rem; top:-4rem; z-index:200;
  background:var(--brand); color:var(--brand-ink);
  padding:.7rem 1.1rem; border-radius:0 0 var(--r) var(--r);
  font-weight:600; font-size:.9rem;
  transition:top .16s ease;
}
.c-skip:focus{top:0; text-decoration:none}

/* A screen's own heading. Each view in the application is a separate page as
   far as a person is concerned, so each one carries an <h1> — but an <h1> at
   full display size would shout on a dashboard. Semantics and size are
   different questions, and this is what answers the second one. */
.c-title{font-size:clamp(1.35rem,2.6vw,1.75rem); letter-spacing:-.022em}

/* A label above a group. Structure, not decoration: it says what the group
   is, so the cards below do not each have to repeat it. */
.c-label{
  font-size:.7rem; font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted); display:block; margin-bottom:.8rem;
}

/* ------------------------------------------------------------- cards */

.c-card{
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:var(--lift);
  padding:clamp(1.1rem,2.6vw,1.6rem);
}
.c-card--flat{box-shadow:none}
.c-card--sunk{background:var(--sunk); box-shadow:none; border-color:transparent}
.c-card--brand{
  background:var(--brand); border-color:var(--brand); color:var(--brand-ink);
  box-shadow:var(--lift-2);
}
.c-card--brand h1,.c-card--brand h2,.c-card--brand h3,.c-card--brand p{color:var(--brand-ink)}
.c-card--brand p{opacity:.85}

/* The widget. Header row, body, optional footer action. This is the shape
   every panel in the application takes. */
.c-widget{
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:var(--lift);
  overflow:hidden;
}
.c-widget__head{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  padding:1.05rem clamp(1.1rem,2.6vw,1.5rem) .5rem;
}
.c-widget__head h2,.c-widget__head h3{font-size:1.02rem; letter-spacing:-.012em}
.c-widget__body{padding:0 clamp(1.1rem,2.6vw,1.5rem) 1.2rem}
.c-widget__foot{
  border-top:1px solid var(--line);
  padding:.9rem clamp(1.1rem,2.6vw,1.5rem);
  background:var(--sunk);
}
.c-widget__foot .c-btn{width:100%}

/* ------------------------------------------------------------- grid */

.c-grid{display:grid; gap:1rem}
@media (min-width:800px){
  .c-grid--2{grid-template-columns:1fr 1fr; align-items:start}
  .c-grid--wide{grid-column:1 / -1}
}
.c-stack{display:flex; flex-direction:column; gap:1rem}
.c-stack--tight{gap:.55rem}
.c-row-gap{display:flex; gap:.6rem; flex-wrap:wrap; align-items:center}

/* ------------------------------------------------------------- buttons */

.c-btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.5rem;
  font-size:.95rem; font-weight:600; letter-spacing:-.005em;
  padding:.85rem 1.5rem; border-radius:var(--r-pill);
  border:1px solid transparent; cursor:pointer; text-decoration:none;
  background:var(--brand); color:var(--brand-ink);
  transition:transform .14s ease, box-shadow .14s ease, background .14s ease;
}
.c-btn:hover{text-decoration:none; transform:translateY(-1px); box-shadow:var(--lift)}
.c-btn:active{transform:none}
.c-btn[disabled]{opacity:.45; cursor:not-allowed; transform:none}
.c-btn--quiet{background:var(--surface); color:var(--ink); border-color:var(--field-line)}
.c-btn--quiet:hover{background:var(--sunk)}
.c-btn--ghost{background:transparent; color:var(--accent); border-color:transparent; padding:.55rem .7rem}
.c-btn--ghost:hover{background:var(--accent-quiet); transform:none; box-shadow:none}
.c-btn--sm{padding:.5rem 1rem; font-size:.85rem}
.c-btn--full{width:100%}

/* ------------------------------------------------------------- chips */

.c-chip{
  display:inline-flex; align-items:center; gap:.35rem;
  font-size:.75rem; font-weight:600; letter-spacing:.01em;
  padding:.3rem .7rem; border-radius:var(--r-pill);
  background:var(--sunk); color:var(--muted); border:1px solid var(--line);
}
.c-chip--good{background:var(--good-bg); color:var(--good); border-color:transparent}
.c-chip--warn{background:var(--warn-bg); color:var(--warn); border-color:transparent}
.c-chip--crit{background:var(--crit-bg); color:var(--crit); border-color:transparent}
.c-chip--accent{background:var(--accent-quiet); color:var(--accent); border-color:transparent}

/* ------------------------------------------------------------- stats */

.c-stats{display:grid; grid-template-columns:repeat(auto-fit,minmax(7.5rem,1fr)); gap:.75rem}
.c-stat{
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r); padding:1rem 1.1rem;
}
.c-stat b{
  display:block; font-size:1.75rem; font-weight:700; line-height:1.05;
  letter-spacing:-.03em; font-variant-numeric:tabular-nums; color:var(--ink);
}
.c-stat span{display:block; font-size:.76rem; color:var(--muted); margin-top:.35rem}

/* ------------------------------------------------------------- rows */

/* A list item: leading badge, title, meta, trailing action. Jobs, roles,
   connections and messages are all this. */
/* A person, and whatever you can do about them.
   ---------------------------------------------------------------------------
   It wraps. On a 420px phone an Accept and a Decline button beside a name left
   the middle column about five characters wide, and the sentence somebody
   wrote asking to connect came out as "We trained / in the / same / place." —
   technically on screen, and unreadable. The buttons drop to their own line
   instead when there is not room for everything. */
.c-item{
  display:flex; flex-wrap:wrap; align-items:center; gap:.85rem;
  padding:.85rem 0; border-top:1px solid var(--line);
}
.c-item:first-child{border-top:none}
.c-list{list-style:none; margin:0; padding:0}

/* Not yet read.
   ---------------------------------------------------------------------------
   A dot AND a heavier weight, not colour on its own: about one man in twelve
   cannot rely on a colour difference, and "which of these have I already seen"
   is exactly the judgement that would become impossible. The dot is drawn
   rather than a character so it does not land in a text selection or get read
   aloud — the state is announced by the visually hidden "unread" beside it. */
.c-item--unread .c-item__title{font-weight:700; color:var(--ink)}
.c-item--unread::before{
  content:""; flex-shrink:0;
  width:.45rem; height:.45rem; border-radius:50%;
  background:var(--accent);
}
/* Read rows indent to match, so the list does not shift as things are read. */
.c-item:not(.c-item--unread)::before{content:""; flex-shrink:0; width:.45rem}

/* A notification row that opens something. A real button, not a div with a
   click handler: it has to be reachable by keyboard, announced as a button,
   and pressable with Enter and Space, and nothing hand-written does all three
   as reliably as the element the browser already ships. */
.c-item__open{
  flex:1; display:block; text-align:left;
  background:none; border:none; padding:0; margin:0;
  font:inherit; color:inherit; cursor:pointer;
}
.c-item__open:hover .c-item__title{color:var(--accent)}

/* ------------------------------------------------------------- a thread

   Who said what is written in words above every message, not signalled only
   by which side of the screen it sits on. Position is invisible to a screen
   reader and hard to rely on for anyone who cannot easily separate two close
   greys — and "who said this" is not a detail in a conversation that may be
   about somebody's immigration status. */
.c-thread{
  margin-top:1.2rem; display:flex; flex-direction:column; gap:.9rem;
  max-height:26rem; overflow-y:auto;
}
.c-msg{max-width:85%; align-self:flex-start}
.c-msg--mine{align-self:flex-end}
.c-msg__who{
  font-size:.68rem; font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; color:var(--muted); margin-bottom:.25rem;
}
.c-msg--mine .c-msg__who{text-align:right}
.c-msg__body{
  background:var(--sunk); color:var(--ink);
  border-radius:var(--r); padding:.7rem .9rem;
  font-size:.95rem; line-height:1.5;
  /* A pasted job description or a long URL must wrap rather than push the
     whole conversation sideways. */
  overflow-wrap:anywhere;
}
.c-msg--mine .c-msg__body{background:var(--accent-quiet)}
.c-item__badge{
  width:2.5rem; height:2.5rem; border-radius:var(--r-sm); flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
  background:var(--accent-quiet); color:var(--accent);
  font-weight:700; font-size:.9rem;
}
/* The same box holding a photo instead of initials. The picture fills it,
   cropped rather than squashed, so a row with a photo and a row without one
   line up and nobody without a photo looks unfinished. The server already
   made the picture square, so the crop here is only a guard. */
.c-item__badge--photo{overflow:hidden; padding:0; background:var(--sunk)}
.c-item__badge--photo img{
  width:100%; height:100%; display:block; object-fit:cover; border-radius:inherit;
}
/* The larger face at the top of a conversation and on the person's own
   profile. Same shape, bigger, and the initials scale with it. */
.c-item__badge--lg{width:3.5rem; height:3.5rem; font-size:1.25rem; border-radius:var(--r)}
/* One line, in the person's own words, under their name. --ink-2 rather than
   --muted: it is the thing they chose to say, not metadata about them. */
.c-item__headline{font-size:.88rem; color:var(--ink-2); margin-top:.15rem; overflow-wrap:anywhere}
/* The head of a conversation: the other person's face beside their name. */
.c-thread__who{display:flex; gap:.9rem; align-items:center; min-width:0}
.c-thread__who > div{min-width:0}
.c-thread__who .c-item__headline{margin-top:.2rem}

/* --------------------------------------------------- how you appear

   The person's own listing, on the Profile screen: the face, the buttons
   that change it, and under them the fields with a switch each. The face
   and its buttons sit side by side where there is room and stack on a
   phone. */
.c-face{display:flex; gap:1rem; align-items:flex-start; flex-wrap:wrap; margin-top:.9rem}
.c-face__acts{flex:1 1 12rem; min-width:0}
.c-face__acts .c-hint{margin-top:.5rem}
/* A field and the switch that shows it, as one group: the switch sits
   directly under the words it governs, so "show this" is never ambiguous
   about which "this". */
.c-appear{margin-top:1.1rem; padding-top:1.1rem; border-top:1px solid var(--line)}
.c-appear .c-check{margin-top:.6rem}
/* A one-tap suggestion under a field: what Cammino would write, offered
   rather than filled in. Ghost, so it reads as an offer, not a default. */
.c-suggest{margin-top:.4rem}
.c-suggest .c-btn{max-width:100%; white-space:normal; text-align:left; line-height:1.35}
/* The preview of the row others see. Set on the sunk ground so it reads as
   a picture of something else, not as one more form section. */
.c-appear__preview{
  margin-top:1.1rem; padding:.9rem 1rem; background:var(--sunk);
  border-radius:var(--r);
}
.c-appear__preview .c-item{padding:0; border:none}
/* 11rem is the basis, not the width: below it the row wraps and the action
   moves to its own line. min-width:0 alone let this column shrink to nothing
   rather than push anything down, which is how the text got crushed. */
.c-item__main{min-width:0; flex:1 1 11rem}
.c-item__title{font-weight:600; font-size:.95rem; color:var(--ink)}
.c-item__meta{font-size:.82rem; color:var(--muted); margin-top:.1rem}
.c-item__note{font-size:.82rem; color:var(--accent); margin-top:.25rem}
.c-item__act{flex-shrink:0}

/* What somebody wrote when they asked to connect. Set apart with a rule down
   the side, because it is another person's words arriving on your screen and
   must not be able to read as Cammino saying something.

   --ink-2, not --muted: this is the sentence the entire decision rests on, and
   it was not rendered at all until tools/drive_messaging.py went looking for
   it. The Connect button asks for it saying "they see this before deciding",
   and they did not. */
.c-item__said{
  margin:.5rem 0 0; padding:.15rem 0 .15rem .7rem;
  border-left:2px solid var(--field-line);
  font-size:.88rem; line-height:1.45; color:var(--ink-2);
  overflow-wrap:anywhere;
}

/* ---------------------------------------------------------- a question

   One interview question, on the preparation screen: the question, why they
   ask, how to answer, what to avoid. Read on a phone the night before, so it
   is set as a document — generous line height, a rule between questions, and
   the question itself in --ink at reading size rather than as a heading
   shouting from a card. Every colour pair here is already measured: --ink,
   --ink-2 and --muted on --surface. */
.c-qa{padding:1rem 0; border-top:1px solid var(--line)}
.c-qa:first-of-type{border-top:none; padding-top:.2rem}
.c-qa__ask{font-size:1rem; line-height:1.4; color:var(--ink); letter-spacing:-.01em}
.c-qa__from{font-size:.8rem; color:var(--muted); margin-top:.25rem}
.c-qa__label{
  font-size:.68rem; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
  color:var(--muted); margin-top:.85rem;
}
.c-qa__text{font-size:.92rem; line-height:1.55; color:var(--ink-2); margin-top:.25rem}
.c-qa__text strong{color:var(--ink)}
.c-qa__list{margin:.3rem 0 0 1.1rem; padding:0; font-size:.92rem; line-height:1.55; color:var(--ink-2)}
.c-qa__list li{margin-top:.2rem}
.c-qa__source{font-size:.78rem; color:var(--muted); margin-top:.7rem; font-style:italic}
/* The numbered lists: the opening's three parts, the answer framework, the
   questions to ask. Numbers matter here — they are the order to say it in. */
.c-qa__steps{margin:.8rem 0 0 1.2rem; padding:0; font-size:.92rem; line-height:1.55; color:var(--ink-2)}
.c-qa__steps li{margin-top:.5rem; padding-left:.2rem}
.c-qa__steps li::marker{color:var(--accent); font-weight:700}

/* ------------------------------------------------------------- a route

   The registration route: numbered, because it is an order — the national
   verification comes before the provincial college, and doing it the other
   way round costs months. Set on a card like everything else; the number sits
   on the accent-quiet ground with accent ink, the pair the badge already
   uses and the contrast test already measures. */
.c-route{
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg);
  box-shadow:var(--lift); padding:clamp(1.1rem,2.6vw,1.5rem);
}
.c-route h2,.c-route h3{font-size:1.02rem; letter-spacing:-.012em; color:var(--ink)}
.c-route h2 a,.c-route h3 a{color:var(--ink)}
.c-route__step{
  display:flex; gap:.75rem; align-items:flex-start;
  margin-top:.9rem; font-size:.92rem; line-height:1.5; color:var(--ink-2);
}
.c-route__step a{font-weight:600}
/* Every link here is the point of the card — the regulator's own site — and
   an inline link is 18px tall, which a shaking hand or a phone thumb misses.
   WCAG 2.2 asks 24px; this pads the hit box without moving the text, the
   negative margin cancelling the padding in the layout. */
.c-route a{display:inline-block; padding:.3rem 0; margin:-.3rem 0}
.c-route__n{
  flex-shrink:0; width:1.6rem; height:1.6rem; border-radius:50%;
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--accent-quiet); color:var(--accent); font-weight:700; font-size:.8rem;
}
.c-route__note{display:block; margin-top:.25rem; font-size:.88rem; color:var(--ink-2)}
.c-route__list{margin:.4rem 0 0 1.1rem; padding:0; font-size:.9rem; line-height:1.5; color:var(--ink-2)}
.c-route__list li{margin-top:.25rem}
.c-route__caveat{font-size:.82rem; line-height:1.5; color:var(--muted); margin-top:.9rem}
.c-route__source{font-size:.78rem; color:var(--muted); margin-top:.5rem; font-style:italic}
.c-route__source a{color:var(--muted); text-decoration:underline}

/* ------------------------------------------------------------- progress */

.c-bar{height:8px; background:var(--sunk); border-radius:var(--r-pill); overflow:hidden}
.c-bar__fill{height:100%; background:var(--accent); border-radius:var(--r-pill);
  transition:width .5s cubic-bezier(.22,.61,.36,1)}
@media (prefers-reduced-motion:reduce){ .c-bar__fill{transition:none} }

/* The journey rail. Numbered because the journey genuinely is a sequence —
   you cannot be diagnosed before you have a goal. */
.c-rail{display:flex; gap:.4rem; list-style:none; margin:0; padding:0}
.c-rail li{
  flex:1; min-width:0; font-size:.7rem; font-weight:600; color:var(--muted);
  padding-top:.55rem; border-top:3px solid var(--line);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.c-rail li.is-done{color:var(--accent); border-top-color:var(--accent)}
.c-rail li.is-now{color:var(--ink); border-top-color:var(--ink)}

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

/* Shown constantly in a product built on progressive personalisation, so it
   is designed rather than left as grey text. It always says what it will
   contain and what unlocks it — never just "nothing here". */
.c-empty{
  border:1px dashed var(--line-2); border-radius:var(--r);
  padding:1.4rem 1.2rem; text-align:center; background:var(--sunk);
}
/* Sized here, levelled by where it sits in the document. */
.c-empty h2{font-size:1.06rem; letter-spacing:-.012em; color:var(--ink); margin-bottom:.3rem}
.c-empty p{font-size:.88rem; color:var(--muted); max-width:30rem; margin:0 auto}
.c-empty .c-btn{margin-top:1rem}

/* ------------------------------------------------------------- notice */

.c-note{
  border-radius:var(--r); padding:.9rem 1.1rem; font-size:.92rem;
  background:var(--accent-quiet); color:var(--ink);
  border-left:3px solid var(--accent);
}
.c-note--warn{background:var(--warn-bg); border-left-color:var(--warn)}
.c-note--crit{background:var(--crit-bg); border-left-color:var(--crit); color:var(--crit)}
.c-note strong{color:inherit}

/* ------------------------------------------------------------- nav */

.c-nav{
  position:sticky; top:0; z-index:50; height:var(--nav-h);
  display:flex; align-items:center; gap:1rem;
  padding:0 clamp(1rem,4vw,2rem);
  background:color-mix(in srgb, var(--ground) 86%, transparent);
  backdrop-filter:saturate(180%) blur(16px);
  -webkit-backdrop-filter:saturate(180%) blur(16px);
  border-bottom:1px solid var(--line);
}
.c-brand{
  font-family:var(--serif); font-size:1.3rem; font-weight:400;
  color:var(--ink); letter-spacing:-.01em; text-decoration:none;
}
.c-brand:hover{text-decoration:none}
.c-nav__spacer{flex:1}
.c-nav__links{display:none; gap:.15rem}
@media (min-width:860px){ .c-nav__links{display:flex} }
.c-nav__link{
  font-size:.9rem; font-weight:600; color:var(--muted);
  padding:.5rem .85rem; border-radius:var(--r-pill); text-decoration:none;
}
.c-nav__link:hover{background:var(--sunk); color:var(--ink); text-decoration:none}
.c-nav__link.is-on{background:var(--sunk); color:var(--ink)}

/* Bottom tabs on a phone. A real floating object, which is what makes an app
   feel like an app rather than a website with links at the top. */
.c-tabs{
  position:fixed; left:50%; transform:translateX(-50%); bottom:.9rem; z-index:60;
  display:flex; gap:.15rem; padding:.35rem;
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-pill); box-shadow:var(--lift-2);
  max-width:calc(100vw - 1.6rem);
}
@media (min-width:860px){ .c-tabs{display:none} }
.c-tab{
  display:flex; flex-direction:column; align-items:center; gap:.15rem;
  /* Horizontal padding gives way before the labels do. With five tabs a fixed
     .95rem overflows a 360px phone, and the bar is centred and fixed, so the
     ends would go off both edges rather than scroll. */
  padding:.5rem clamp(.5rem, 3.2vw, .95rem);
  border-radius:var(--r-pill);
  font-size:.66rem; font-weight:600; color:var(--muted);
  text-decoration:none; border:none; background:none; cursor:pointer;
  position:relative;
}
.c-tab svg{width:20px; height:20px; stroke:currentColor; fill:none; stroke-width:1.8}
.c-tab.is-on{background:var(--sunk); color:var(--ink)}
.c-tab:hover{text-decoration:none}

/* How many things are waiting.
   ---------------------------------------------------------------------------
   On the accent rather than a red: nothing here is an alarm. Somebody has a
   message, which is the good outcome of a product about getting in touch, and
   dressing it as an error trains people to feel dread when the number moves.

   The number alone is not the message — a screen reader announces the tab's
   own aria-label, which shell.js writes as "Network, 3 new". This is aria-hidden
   so the count is not read out twice. */
.c-badge{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:1.15rem; height:1.15rem; padding:0 .3rem;
  border-radius:var(--r-pill);
  background:var(--accent); color:var(--brand-ink);
  font-size:.62rem; font-weight:700; font-variant-numeric:tabular-nums;
  line-height:1;
}
/* In the bottom bar it sits on the icon; in the desktop nav it follows the
   word, because there is room for it there and a floating badge beside a text
   link reads as a mistake. */
.c-tab .c-badge{position:absolute; top:.22rem; right:.5rem}
.c-nav__link .c-badge{margin-left:.4rem}

/* The theme control. Permanent, not a comparison switch: both themes are
   the product, and the person picks. */
.c-theme{
  display:inline-flex; padding:.2rem; gap:.1rem;
  background:var(--sunk); border-radius:var(--r-pill); border:1px solid var(--line);
}
.c-theme button{
  border:none; background:none; cursor:pointer; border-radius:var(--r-pill);
  padding:.35rem .6rem; color:var(--muted); display:flex; align-items:center;
}
.c-theme button svg{width:15px; height:15px; stroke:currentColor; fill:none; stroke-width:1.8}
.c-theme button.is-on{background:var(--surface); color:var(--ink); box-shadow:var(--lift)}

/* ------------------------------------------------------------- sections */

.c-section{padding:clamp(1.6rem,4vw,2.6rem) 0}
.c-page{padding-bottom:6rem}
@media (min-width:860px){ .c-page{padding-bottom:3rem} }

/* ------------------------------------------------------------- public */

/* The one place the serif is used, because the public page has a voice and
   the application has a job. */
.p-hero{padding:clamp(2.6rem,8vw,5.5rem) 0 clamp(2rem,5vw,3.5rem)}
.p-hero h1{
  font-family:var(--serif); font-weight:300; letter-spacing:-.03em;
  font-size:clamp(2.5rem,6.4vw,4.4rem); line-height:1.04; max-width:15ch;
}
.p-hero h1 em{font-style:italic; color:var(--accent)}
.p-lede{font-size:clamp(1.05rem,1.6vw,1.22rem); color:var(--muted);
  max-width:34rem; margin-top:1.3rem}
.p-acts{display:flex; gap:.7rem; flex-wrap:wrap; align-items:center; margin-top:2rem}
.p-acts small{color:var(--muted); font-size:.85rem}

.p-step{display:flex; gap:1rem; align-items:flex-start}
.p-step__n{
  flex-shrink:0; width:2rem; height:2rem; border-radius:var(--r-pill);
  background:var(--brand); color:var(--brand-ink);
  display:flex; align-items:center; justify-content:center;
  font-size:.85rem; font-weight:700; font-variant-numeric:tabular-nums;
}
.p-step h3{margin-bottom:.2rem}
.p-step p{font-size:.94rem; color:var(--muted)}

.p-foot{border-top:1px solid var(--line); padding:2rem 0 3rem;
  color:var(--muted); font-size:.85rem}

/* ------------------------------------------------------------- forms */

label{display:block; font-weight:600; font-size:.9rem; color:var(--ink); margin-bottom:.4rem}
input[type="text"],input[type="email"],input[type="password"],
input[type="number"],input[type="month"],select,textarea{
  width:100%; font-family:var(--sans); font-size:1rem; color:var(--ink);
  background:var(--surface); border:1px solid var(--field-line);
  border-radius:var(--r); padding:.8rem 1rem;
  transition:border-color .15s ease, box-shadow .15s ease;
}
input::placeholder,textarea::placeholder{color:var(--muted)}
input:focus,select:focus,textarea:focus{
  outline:none; border-color:var(--accent);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
textarea{min-height:11rem; resize:vertical; line-height:1.55}
select option{background:var(--surface); color:var(--ink)}
/* 24px, which is WCAG 2.2's minimum target size and also just easier to hit.
   It was 13px — the browser default — on the age confirmation that stands
   between somebody and an account. */
input[type="checkbox"]{
  width:1.5rem; height:1.5rem; min-width:1.5rem; flex:none;
  accent-color:var(--accent); cursor:pointer;
}
/* A checkbox and the words beside it, as one target. The profile's email
   switch used to borrow .funnel-row — a label on the left and a number box on
   the right — which put the box in the wide column and crushed the words into
   the narrow one. Seen in the screenshots while making the first preview. */
.c-check{display:flex; gap:.7rem; align-items:flex-start; cursor:pointer; margin:0;
  font-size:.95rem; font-weight:500; color:var(--ink)}
.c-check input{margin-top:.1rem}
.c-check .sub{display:block; font-size:.85rem; color:var(--muted); font-weight:400; margin-top:.2rem}
.c-field{margin-bottom:1.1rem}
.c-hint{font-size:.85rem; color:var(--muted); margin-top:.3rem}

/* A choice, as a real target rather than a radio button. */
.c-choice{
  display:block; width:100%; text-align:left; cursor:pointer;
  background:var(--surface); border:1px solid var(--field-line);
  border-radius:var(--r); padding:1rem 1.15rem;
  transition:border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.c-choice:hover{border-color:var(--accent); transform:translateY(-1px)}
.c-choice.is-on{border-color:var(--accent);
  box-shadow:0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent)}
.c-choice strong{display:block; font-size:.98rem; color:var(--ink); font-weight:600}
.c-choice span{display:block; font-size:.87rem; color:var(--muted); margin-top:.2rem}

/* ------------------------------------------------------------- overlay */

.c-overlay{
  position:fixed; inset:0; z-index:90; display:none;
  align-items:center; justify-content:center; padding:1rem;
  background:color-mix(in srgb, var(--ink) 42%, transparent);
  backdrop-filter:blur(5px); -webkit-backdrop-filter:blur(5px);
}
.c-overlay.is-open{display:flex}
.c-dialog{
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-xl); box-shadow:var(--lift-2);
  padding:clamp(1.4rem,4vw,2rem); width:100%; max-width:26rem;
  max-height:90svh; overflow-y:auto;
}
.c-dialog h2{font-size:1.4rem; margin-bottom:.4rem}

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

.c-rise{opacity:0; transform:translateY(.8rem);
  transition:opacity .6s cubic-bezier(.22,.61,.36,1), transform .6s cubic-bezier(.22,.61,.36,1)}
.c-rise.is-in{opacity:1; transform:none}
@media (prefers-reduced-motion:reduce){
  .c-rise{opacity:1; transform:none; transition:none}
  .c-btn,.c-choice{transition:none}
}

/* Wide content never makes the page scroll sideways. */
.c-scroll{overflow-x:auto; -webkit-overflow-scrolling:touch}

/* =========================================================================
   The engine's own markup, restyled.

   app.js and dashboard.js emit about ninety class names from the old
   stylesheet. Rewriting those render functions would mean re-testing the
   diagnostic, the four-part report and the whole dashboard — work with real
   risk and no visible reward.

   So instead the old class names are mapped onto the new components here.
   This is not the layering mistake from before: the old stylesheet is no
   longer loaded at all. These ARE the definitions, written in the new system,
   and the JS simply happens to use older names for them.
   ========================================================================= */

.wrap{max-width:64rem; margin:0 auto; padding:0 clamp(1rem,4vw,2rem)}
.screen{display:none; padding:clamp(1.4rem,4vw,2.4rem) 0 5rem}
.screen.active{display:block}
@media (min-width:860px){ .screen{padding-bottom:3rem} }

.card,.plan-card,.route-card,.review-card,.empty-card,.clean-card,.acc__item{
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg); box-shadow:var(--lift);
  padding:clamp(1.1rem,2.6vw,1.5rem); margin-top:1rem;
}
.card__head{display:flex; align-items:flex-start; justify-content:space-between;
  gap:.8rem; margin-bottom:.5rem}
.section{margin-top:clamp(1.6rem,4vw,2.4rem)}
.section > h2{margin-bottom:.3rem}

/* The report hero. Inverted in both themes, because it is the one moment the
   product speaks rather than reports. */
.result-hero,.hero-card,.dash-hero,.waitlist-card{
  background:var(--brand); color:var(--brand-ink);
  border:1px solid var(--brand); border-radius:var(--r-xl);
  box-shadow:var(--lift-2); padding:clamp(1.4rem,4vw,2.2rem);
}
.result-hero h1,.result-hero h2,.hero-card h1,.dash-hero h1,.dash-hero h2,
.waitlist-card h2{color:var(--brand-ink)}
.result-hero p,.hero-card p,.dash-hero p,.waitlist-card p{color:var(--brand-ink); opacity:.85}
.result-hero .eyebrow,.dash-hero .eyebrow,.hero-card .eyebrow{color:var(--brand-ink); opacity:.6}

/* The diagnosis is four separate paragraphs making four separate points, and
   the global margin reset left them with no space between them — so they
   rendered as one unbroken block, on the single screen a person reads most
   carefully. The first paragraph is the finding, so it gets to be bigger. */
/* 44rem, not 62ch. This font's `0` is narrow, so 62ch measured about
   26 characters short and left the paragraphs hugging the left half of a
   card whose heading spans all of it. */
.result-body{margin-top:1rem; max-width:44rem}
.result-body p + p{margin-top:.85rem}
.result-body p:first-child{font-size:1.06rem}
.stage-strip{display:flex; gap:.5rem; flex-wrap:wrap; margin-top:1.2rem;
  padding-top:1.2rem; border-top:1px solid color-mix(in srgb, var(--brand-ink) 18%, transparent)}
.chip{display:inline-flex; align-items:center; font-size:.78rem; font-weight:600;
  padding:.35rem .8rem; border-radius:var(--r-pill);
  background:color-mix(in srgb, var(--brand-ink) 12%, transparent);
  color:var(--brand-ink);
  border:1px solid color-mix(in srgb, var(--brand-ink) 20%, transparent)}

.eyebrow,.part-pill{font-size:.7rem; font-weight:700; letter-spacing:.14em;
  text-transform:uppercase; color:var(--muted); display:inline-block}
.part-pill{background:var(--sunk); color:var(--muted); padding:.35rem .8rem;
  border-radius:var(--r-pill); border:1px solid var(--line)}
.hint,.step-count,.role__meta,.stat__label,.stat__note,.disclaimer,
.signup-note,.foot{color:var(--muted); font-size:.88rem}
.tagline{color:var(--accent); font-size:.88rem}
.lede{color:var(--muted); font-size:1.02rem}

.btn{display:inline-flex; align-items:center; justify-content:center; gap:.5rem;
  font-size:.95rem; font-weight:600; padding:.85rem 1.5rem; border:1px solid transparent;
  border-radius:var(--r-pill); cursor:pointer; background:var(--brand);
  color:var(--brand-ink); transition:transform .14s ease, box-shadow .14s ease}
.btn:hover{transform:translateY(-1px); box-shadow:var(--lift)}
.btn[disabled]{opacity:.45; cursor:not-allowed; transform:none}
.btn--accent{background:var(--brand); color:var(--brand-ink)}
.btn--quiet{background:var(--surface); color:var(--ink); border-color:var(--field-line)}
.btn--quiet:hover{background:var(--sunk)}
.btn--wide{width:100%}
.ghost-btn{background:var(--surface); border:1px solid var(--field-line); color:var(--muted);
  font-size:.85rem; font-weight:600; padding:.5rem 1rem;
  border-radius:var(--r-pill); cursor:pointer}
.ghost-btn:hover{color:var(--ink); background:var(--sunk)}
.ghost-btn--solid{background:var(--brand); border-color:var(--brand); color:var(--brand-ink)}
.link-btn{background:none; border:none; color:var(--accent); font-size:.88rem;
  cursor:pointer; padding:.3rem; text-decoration:underline}
.nav-row{display:flex; gap:.7rem; margin-top:1.6rem; align-items:center; flex-wrap:wrap}
@media (max-width:560px){
  .nav-row{flex-direction:column-reverse; align-items:stretch}
  .nav-row .btn{width:100%}
}

.choices{display:grid; gap:.6rem; margin-top:.8rem}
.choice{display:block; width:100%; text-align:left; cursor:pointer;
  background:var(--surface); border:1px solid var(--field-line);
  border-radius:var(--r); padding:1rem 1.15rem;
  transition:border-color .15s ease, transform .15s ease}
.choice:hover{border-color:var(--accent); transform:translateY(-1px)}
.choice.selected{border-color:var(--accent);
  box-shadow:0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent)}
.choice strong{display:block; font-size:.98rem; font-weight:600; color:var(--ink)}
.choice span{display:block; font-size:.87rem; color:var(--muted); margin-top:.2rem}

.field{margin-top:1.2rem}
.field > label,.field-label{display:block; font-weight:600; font-size:.9rem;
  color:var(--ink); margin-bottom:.4rem}
.grid-2{display:grid; grid-template-columns:1fr 1fr; gap:.8rem}
.grid-funnel{display:grid; gap:.7rem}
.funnel-row{display:grid; grid-template-columns:1fr 110px; gap:.8rem; align-items:center;
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r); padding:.8rem 1rem}
.funnel-row label{font-size:.92rem; color:var(--ink); font-weight:500; margin:0}
.funnel-row .sub{display:block; font-size:.8rem; color:var(--muted); font-weight:400}
.funnel-row input{text-align:center; padding:.5rem}

.progress{height:6px; background:var(--sunk); border-radius:var(--r-pill); overflow:hidden}
.progress__bar{height:100%; background:var(--accent); width:0%; transition:width .4s ease}
.meter-row{display:grid; gap:.7rem; margin-top:1rem}
.meter__label{font-size:.8rem; color:var(--muted); display:block; margin-bottom:.3rem}
.meter__track,.funnel-bar__track{height:8px; background:var(--sunk);
  border-radius:var(--r-pill); overflow:hidden}
.meter__fill{height:100%; background:var(--accent); border-radius:var(--r-pill)}
.funnel-bar__fill{height:100%; background:var(--brand); border-radius:var(--r-pill)}
.meter__value,.funnel-bar__value{font-size:.82rem; font-weight:600; color:var(--ink);
  font-variant-numeric:tabular-nums}

.tag{display:inline-flex; align-items:center; font-size:.74rem; font-weight:600;
  padding:.3rem .7rem; border-radius:var(--r-pill); white-space:nowrap;
  background:var(--sunk); color:var(--muted); border:1px solid var(--line)}
.tag--now{background:var(--good-bg); color:var(--good); border-color:transparent}
.tag--soon{background:var(--warn-bg); color:var(--warn); border-color:transparent}
.tag--later,.tag--ctrl{background:var(--sunk); color:var(--muted)}
.sev--fix{background:var(--crit-bg); color:var(--crit)}
.sev--worth{background:var(--warn-bg); color:var(--warn)}
.sev--polish{background:var(--sunk); color:var(--muted)}

.notice{border-radius:var(--r); padding:.9rem 1.1rem; font-size:.92rem;
  background:var(--accent-quiet); color:var(--ink);
  border-left:3px solid var(--accent); margin-top:1rem}
.notice.warn{background:var(--warn-bg); border-left-color:var(--warn)}
.notice.error{background:var(--crit-bg); border-left-color:var(--crit); color:var(--crit)}
/* "Your request went through", as distinct from "here is a fact". Used by the
   forgot-password screen, where the message is deliberately conditional — the
   green says the form worked, and the words stay careful about what that
   means. */
.notice.ok{background:var(--good-bg); border-left-color:var(--good); color:var(--good)}

.evidence{margin-top:1rem; padding-top:.9rem; border-top:1px solid var(--line)}
.evidence h4{font-size:.78rem; letter-spacing:.1em; text-transform:uppercase;
  color:var(--muted); margin-bottom:.4rem}
.evidence ul{margin:0; padding-left:1.1rem}
.evidence li{font-size:.9rem; color:var(--ink-2); margin-bottom:.25rem}
.evidence.against li{color:var(--muted)}

.role{display:grid; grid-template-columns:2rem 1fr; gap:.9rem; align-items:start}
.role__num{font-size:1.05rem; font-weight:700; color:var(--accent);
  font-variant-numeric:tabular-nums}
.role__body h3{margin-bottom:.2rem}

.stat-row,.c-stats{display:grid; grid-template-columns:repeat(auto-fit,minmax(7.5rem,1fr)); gap:.7rem}
.stat{background:var(--surface); border:1px solid var(--line); border-radius:var(--r);
  padding:1rem; margin:0}
.stat__value{display:block; font-size:1.6rem; font-weight:700; line-height:1.05;
  letter-spacing:-.03em; color:var(--ink); font-variant-numeric:tabular-nums}
.funnel-bar__label{font-size:.85rem; color:var(--ink)}
.funnel-row,.conv-list strong,.task strong,.hist__meta strong{color:var(--ink)}
.task{display:flex; gap:.7rem; align-items:flex-start; padding:.85rem 0;
  border-top:1px solid var(--line); margin:0; background:none; box-shadow:none;
  border-radius:0; border-left:none; border-right:none; border-bottom:none}
.task:first-child{border-top:none}
.task strong{display:block; font-size:.94rem; font-weight:600; line-height:1.45}
.task--done strong{opacity:.55; text-decoration:line-through}

/* A real button now, so it needs the reset a button needs. */
.upload-zone{display:block; width:100%; font-family:inherit; line-height:1.55;
  border:1px dashed var(--field-line); border-radius:var(--r);
  background:var(--sunk); padding:1.1rem; text-align:center; font-size:.92rem;
  color:var(--muted); cursor:pointer}
.upload-zone strong{color:var(--ink)}
.upload-zone:hover{border-color:var(--accent); color:var(--ink-2)}
.upload-zone:hover,.upload-zone.drag{border-color:var(--accent); background:var(--accent-quiet)}
.upload-zone strong{color:var(--ink)}

.analyzing{text-align:center; padding:4rem 0}
.pulse{width:48px; height:48px; border-radius:50%; background:var(--accent);
  margin:0 auto 1.4rem; animation:c-pulse 1.5s ease-in-out infinite}
@keyframes c-pulse{0%,100%{opacity:.28; transform:scale(.9)}50%{opacity:1; transform:scale(1)}}
@media (prefers-reduced-motion:reduce){ .pulse{animation:none; opacity:.7} }

.photo-card{border-radius:var(--r-lg); overflow:hidden; border:1px solid var(--line);
  box-shadow:var(--lift); margin-top:1rem}
.photo-card img{display:block; width:100%; height:auto}
.overlay{position:fixed; inset:0; z-index:90; display:none; align-items:center;
  justify-content:center; padding:1rem;
  background:color-mix(in srgb, var(--ink) 42%, transparent);
  backdrop-filter:blur(5px); -webkit-backdrop-filter:blur(5px)}
.overlay.open{display:flex}
.dialog{background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-xl); box-shadow:var(--lift-2);
  padding:clamp(1.4rem,4vw,2rem); width:100%; max-width:28rem;
  max-height:90svh; overflow-y:auto; position:relative}
.dialog .close{position:absolute; top:1rem; right:1rem}

.mt-s{margin-top:.5rem} .mt-m{margin-top:1rem} .mt-l{margin-top:1.6rem}
.joblink{display:flex; gap:.85rem; align-items:center; padding:.85rem 0;
  border-top:1px solid var(--line)}
.joblink:first-of-type{border-top:none}
.joblink .co{width:2.5rem; height:2.5rem; border-radius:var(--r-sm); flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
  background:var(--accent-quiet); color:var(--accent); font-weight:700; font-size:.9rem}
.joblink .t{font-weight:600; font-size:.95rem; color:var(--ink)}
.joblink .m{font-size:.82rem; color:var(--muted)}
.joblink .why{font-size:.82rem; color:var(--accent); margin-top:.2rem}
.joblink a{margin-left:auto; flex-shrink:0}
.src,.joblink-src{font-size:.78rem; color:var(--muted); margin-top:.9rem;
  padding-top:.8rem; border-top:1px solid var(--line)}
.joblink-out{color:var(--accent); font-weight:600}
.joblink-src{border:none; padding:0; margin-top:.2rem; display:block}

/* On a 390px phone the brand, the theme control and two buttons run about
   27px past the edge. The sign-in link is the one to drop: it is reachable
   from the account screen itself, and "Get started" is what a first-time
   visitor is there for. */
@media (max-width:560px){
  .c-nav{gap:.5rem; padding:0 1rem}
  .c-nav [href*="signin"]{display:none}
  .c-nav .c-btn--sm{padding:.5rem .9rem; font-size:.84rem}
  .c-brand{font-size:1.15rem}

  /* Signed in, the bar carries brand + theme + Engine + Sign out and runs
     59px past the edge. The engine chooser is a developer control, and
     signing out belongs on the Profile screen where people look for it —
     which is where it now lives, on every width. */
  .c-nav #settingsBtn,
  .c-nav #signOutBtn{display:none}
}

/* =========================================================================
   Photographs

   The site is designed to be good without them and better with them. The
   images are not committed — `python setup.py` fetches them — so
   every slot has to hold its shape when the file is not there yet.

   That is what .c-figure does. The gradient is the surface; the photograph
   lays over it. If the file is missing the img is hidden by its own onerror
   and the gradient remains, which reads as a deliberate colour panel rather
   than a broken image icon. Nothing shifts, nothing jumps.

   The gradients are not random: each is derived from the brand blues, so an
   un-fetched site looks like a decision instead of an accident.
   ========================================================================= */

.c-figure{
  position:relative; overflow:hidden;
  border-radius:var(--r-lg);
  /* Strong enough to read as a chosen colour panel. At 20% it looked like a
     failed image; the whole point is that a site with no photographs yet
     still looks finished. */
  background:linear-gradient(140deg,
    color-mix(in srgb, var(--accent) 62%, var(--brand)),
    color-mix(in srgb, var(--brand) 92%, var(--accent)));
  isolation:isolate;
}
.c-figure::after{
  /* A faint grain over the gradient so an empty slot has texture rather than
     reading as a flat swatch. Costs nothing; it is one inline SVG. */
  content:''; position:absolute; inset:0; pointer-events:none; opacity:.5;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='2'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='.22'/%3E%3C/svg%3E");
}
.c-figure img{
  display:block; width:100%; height:100%; object-fit:cover;
  position:relative; z-index:1;
}
.c-figure--tall{aspect-ratio:3 / 4}
.c-figure--wide{aspect-ratio:16 / 10}
.c-figure--square{aspect-ratio:1 / 1}
.c-figure--hero{aspect-ratio:4 / 5}
@media (max-width:800px){
  .c-figure--hero{aspect-ratio:16 / 10}
}

/* A caption that sits on the image. Used only for descriptive text — never
   for a claim, a quote or a name, because a face plus a claim reads as a
   testimonial and neither the licence nor Canadian personality rights allow
   that. See image-credits.md. */
.c-figure figcaption{
  position:absolute; left:0; right:0; bottom:0; z-index:2;
  padding:2.2rem 1.1rem .95rem;
  font-size:.82rem; font-weight:600; color:#fff;
  background:linear-gradient(to top, rgba(6,18,28,.82), rgba(6,18,28,0));
}

/* The hero: statement on one side, photograph on the other. */
.p-hero__grid{display:grid; gap:clamp(1.5rem,4vw,3rem); align-items:center}
@media (min-width:900px){
  .p-hero__grid{grid-template-columns:1.15fr .85fr}
}

/* An alternating story section. The image side swaps every other one, which
   is what stops a long page reading as a list. */
.p-story{display:grid; gap:clamp(1.2rem,3vw,2.5rem); align-items:center;
  padding:clamp(1.6rem,4vw,2.6rem) 0}
@media (min-width:820px){
  .p-story{grid-template-columns:1fr 1fr}
  .p-story--flip .p-story__text{order:2}
  .p-story--flip .p-story__img{order:1}
}
.p-story h2{font-size:clamp(1.5rem,3vw,2.1rem)}
.p-story p{margin-top:.6rem; color:var(--muted); max-width:38rem}

/* A person-card: photo above, text below. Used for "who it's for", where the
   copy is descriptive and the face is atmospheric. */
.c-persona{
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg); overflow:hidden; box-shadow:var(--lift);
  display:flex; flex-direction:column;
}
/* 16/10 rather than 4/3: on a half-width card a 4:3 image pushed the heading
   most of a screen down, so the reason to read the card arrived after the
   picture had already used up the viewport. */
.c-persona .c-figure{border-radius:0; aspect-ratio:16 / 10}
.c-persona__body{padding:1.1rem 1.2rem 1.3rem}
.c-persona h3{margin-bottom:.3rem}
.c-persona p{font-size:.88rem; color:var(--muted)}

/* The journey band: five beats, shown as a path rather than a list, because
   the product's whole claim is that this is a sequence you move along. */
.p-path{
  display:grid; gap:.5rem; counter-reset:beat;
  grid-template-columns:repeat(auto-fit,minmax(9rem,1fr));
}
.p-path li{
  list-style:none; position:relative; padding:1.1rem 1rem 1.2rem;
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r);
}
.p-path li::before{
  counter-increment:beat; content:counter(beat);
  display:flex; align-items:center; justify-content:center;
  width:1.7rem; height:1.7rem; border-radius:var(--r-pill);
  background:var(--accent-quiet); color:var(--accent);
  font-size:.78rem; font-weight:700; margin-bottom:.6rem;
}
.p-path strong{display:block; font-size:.95rem; color:var(--ink)}
.p-path span{display:block; font-size:.83rem; color:var(--muted); margin-top:.2rem}

/* =========================================================================
   The report and the intake

   These two screens were the last things still rendering as the old design
   with new colours on top. They are also the two a person spends the longest
   inside, so they were the worst place to leave that.

   The finding card is the centrepiece. Before, each one carried two
   full-width meter bars — with four or five findings that is ten bars down
   the page, and the eye stops reading them by the third. Likelihood is now a
   single bar because it is the number that ranks the list; confidence is a
   word, because "moderate confidence" is what a person actually needs and
   a second bar next to the first invites a comparison that means nothing.
   ========================================================================= */

/* The part marker. This is a four-part report and the order carries meaning,
   so the number is information rather than decoration. */
.r-part{
  display:flex; align-items:baseline; gap:.7rem;
  padding-bottom:.9rem; margin-bottom:1.4rem;
  border-bottom:1px solid var(--line);
}
.r-part b{
  font-family:var(--mono); font-size:.72rem; font-weight:500;
  letter-spacing:.1em; color:var(--accent);
}
.r-part span{font-size:.72rem; letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted); font-weight:700}

/* A finding: one thing the engine thinks is happening. */
.r-finding{
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg); box-shadow:var(--lift);
  padding:clamp(1.1rem,2.6vw,1.5rem); margin-top:.85rem;
}
.r-finding__head{
  display:flex; align-items:flex-start; justify-content:space-between;
  gap:.9rem; margin-bottom:.5rem;
}
.r-finding__head h3{font-size:1.05rem}
.r-finding > p{font-size:.95rem; color:var(--ink-2)}

/* Likelihood and confidence, on one line. The bar ranks; the word explains. */
/* The two numbers a finding carries, on two lines. They answer different
   questions — how probable is this, and how sure are we — so they are not
   drawn on the same scale and never side by side competing for width. */
.r-readout{
  margin-top:1rem; padding-top:.9rem; border-top:1px solid var(--line);
  display:grid; gap:.5rem;
}
.r-readout__row{display:grid; grid-template-columns:8.5rem 1fr auto; gap:.85rem;
  align-items:center}
.r-readout__key{
  font-size:.7rem; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  color:var(--muted);
}
.r-readout__row b{font-family:var(--mono); font-size:.86rem; color:var(--ink);
  font-variant-numeric:tabular-nums; font-weight:600}
.r-readout__row--conf{grid-template-columns:8.5rem 1fr}
.r-readout__row--conf span:last-child{font-size:.88rem; color:var(--ink-2)}
@media (max-width:560px){
  .r-readout__row,.r-readout__row--conf{grid-template-columns:1fr auto; gap:.4rem}
  .r-readout__key{grid-column:1 / -1}
  .r-readout__row--conf span:last-child{grid-column:1 / -1}
}

/* Evidence, two columns where there is room. Side by side is the point: what
   points this way and what argues against it are a pair, and stacking them
   makes the second look like an afterthought. */
.r-evidence{display:grid; gap:.9rem; margin-top:1rem}
@media (min-width:680px){ .r-evidence--pair{grid-template-columns:1fr 1fr} }
.r-evidence section{
  background:var(--sunk); border-radius:var(--r); padding:.85rem 1rem;
}
.r-evidence h4{
  font-size:.68rem; letter-spacing:.11em; text-transform:uppercase;
  color:var(--muted); margin-bottom:.45rem; font-weight:700;
}
.r-evidence ul{margin:0; padding-left:1rem}
.r-evidence li{font-size:.87rem; color:var(--ink-2); margin-bottom:.3rem}
.r-evidence li:last-child{margin-bottom:0}
.r-code{
  font-family:var(--mono); font-size:.68rem; color:var(--muted);
  margin-top:.9rem; display:block;
}

/* ------------------------------------------------------------- intake */

/* One question at a time, in a card, with the progress above it. The old
   version put a bare progress bar and a naked form on the page background,
   which made a five-minute questionnaire feel like a government form. */
.i-shell{max-width:40rem; margin:0 auto}
.i-progress{margin-bottom:1.3rem}
.i-progress__meta{
  display:flex; justify-content:space-between; align-items:baseline;
  margin-bottom:.5rem; font-size:.76rem; color:var(--muted);
}
.i-progress__meta b{font-family:var(--mono); font-weight:500; color:var(--ink)}
.i-card{
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-xl); box-shadow:var(--lift);
  padding:clamp(1.3rem,3.5vw,2rem);
}
.i-card h2{font-size:clamp(1.3rem,2.8vw,1.7rem); margin-bottom:.4rem}
.i-card > .hint:first-of-type{margin-bottom:1.2rem}

/* The intake's own nav sits under the card, not inside it, so the card is
   the question and the buttons are the answer to "what now". */
#screen-intake .nav-row{max-width:40rem; margin-left:auto; margin-right:auto}
