/* Prudence web app: one calm, high-contrast look for people 60+.
   Written 2026-10-27 from the Claude Design mockups: verdict first, solid
   red only for Scam, colour always paired with a word, 64px main buttons,
   no small print. Re-skinned 2026-11-04 to the redesign canvas
   (_product/design/2026-11-04-redesign/claude-design/): the header with one
   Settings button, four tabs, and the shared components at the end of this
   file ("2026-11-04 redesign: shared components").

   Text sizes. The person picks Normal, Larger or Largest (user.textScale 1,
   1.2, 1.4); js/main.js applyPrefs() turns it into two values:
   - the root font size, 19px x textScale: everything in rem grows with it.
     This is the canvas's --s (its calc(22px * var(--s)) is calc(22rem / 19)
     here; the --t19 ... --t36 tokens below spell the canvas sizes). Body
     text, cards, buttons and titles are in rem.
   - --u on <body>, 1, 1.1 or 1.2 (the canvas's --u): the header and the tab
     bar are in calc(Npx * var(--u)), so at Largest their labels grow by a
     fifth, not two fifths, and never wrap or get cut (frame 1c).
   --s is set on <body> too (= textScale), for a value copied from the
   canvas as calc(Npx * var(--s)); prefer the rem tokens. */

/* Atkinson Hyperlegible Next, drawn by the Braille Institute for low-vision
   readers (letters that cannot be mistaken: I l 1, O 0, rn m). Self-hosted,
   SIL Open Font License 1.1 (public/fonts/OFL.txt), Latin subset from
   @fontsource/atkinson-hyperlegible-next 5.3.0. */
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/atkinson-hyperlegible-next-400.woff2") format("woff2");
}
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/atkinson-hyperlegible-next-700.woff2") format("woff2");
}

:root {
  --navy: #16283f;
  --navy-deep: #0f1d2f;
  --navy-wash: #eef4fb;
  --gold: #e9a820;
  --gold-hover: #d99a12;
  --gold-wash: #fdf4dd;
  --surface: #ffffff;
  --ground: #eef1f5;
  --ink: #1a1a1a;
  --muted: #4a4a4a;
  --line: #d8dee6;
  --field: #8a97a8;
  --scam: #b42318;
  --scam-ink: #7a1710;
  --scam-wash: #fef3f2;
  --careful: #b54708;
  --careful-ink: #7a3a06;
  --careful-wash: #fffaeb;
  --safe: #067647;
  --safe-ink: #054f31;
  --safe-wash: #ecfdf3;
  --focus-ring: #ffbf47;
  --round: 16px;
  --round-small: 12px;
  --soon: #e6eaef;          /* the grey of every Coming soon row and button */
  /* The canvas's type sizes at Normal, in rem so they follow the text size. */
  --t19: 1rem;              /* states, pills, sub-lines */
  --t22: calc(22rem / 19);  /* body, row names, buttons */
  --t24: calc(24rem / 19);  /* big choice buttons */
  --t26: calc(26rem / 19);  /* card headlines */
  --t28: calc(28rem / 19);  /* the Today card title */
  --t32: calc(32rem / 19);  /* screen titles */
  --t36: calc(36rem / 19);  /* the verdict word */
  --type: "Atkinson Hyperlegible Next", "Atkinson Hyperlegible", Verdana, "Segoe UI", system-ui, sans-serif;
}

*,
*::before,
*::after { box-sizing: border-box; }

html { font-size: 19px; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--type);
  line-height: 1.5;
}

h1, h2, h3 { font-family: var(--type); line-height: 1.2; }

button, input, select, textarea { font: inherit; color: inherit; }

/* Gold next to the control, navy outside it: one of the two always shows,
   on the light ground, on navy bars and on gold buttons (3:1 or better). */
:focus-visible { outline: 3px solid var(--navy); outline-offset: 3px; box-shadow: 0 0 0 3px var(--focus-ring); }

/* ------------------------------------------------------------ header -- */

/* PrudenceHeader: navy, 16px all round, the gold 44px check circle and
   "Prudence" on the left; on the right the senior's one Settings button (gear
   and the word, 64px, white 2px outline, gold when Settings is open), or the
   language button (signed out, demo), or plain links (trusted person, admin).
   Sizes in px x --u: see "Text sizes" at the top. */
.topbar {
  background: var(--navy);
  color: var(--surface);
  padding: 16px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
}

.brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
a.brand { color: var(--surface); text-decoration: none; }
.brand-words { min-width: 0; }

.shield {
  width: 44px;
  height: 44px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--gold);
  color: var(--navy-deep);
  font-size: 1.5rem; /* the text tick of privacy.html and terms.html */
  font-weight: 700;
}

.brand-name { margin: 0; font-size: calc(22px * var(--u, 1)); font-weight: 700; line-height: 1.1; white-space: nowrap; }
.brand-sub { margin: 0.15rem 0 0; color: #dbe6f2; font-size: 1rem; }

.top-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.who { color: #dbe6f2; font-size: 1rem; }
.who:empty { display: none; }

.nav { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.nav-link {
  display: inline-flex;
  align-items: center;
  min-height: 64px;
  padding: 0 14px;
  border-radius: 16px;
  color: var(--surface);
  font-size: calc(19px * var(--u, 1));
  font-weight: 700;
  white-space: nowrap;
  text-decoration: none;
}
.nav-link:hover { text-decoration: underline; text-underline-offset: 4px; }
.nav-link.active { background: var(--gold); color: var(--navy-deep); }
.nav-link.active:hover { text-decoration: none; background: var(--gold-hover); }

/* The senior's Settings button: a link that looks like the canvas's button. */
.top-settings {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 8px;
  min-height: 64px;
  padding: 0 14px;
  border: 2px solid var(--surface);
  border-radius: 16px;
  background: transparent;
  color: var(--surface);
  font-size: calc(19px * var(--u, 1));
  font-weight: 700;
  line-height: 1.1;
  white-space: nowrap;
  text-decoration: none;
}
.top-settings svg { flex: none; }
.top-settings:hover { background: rgba(255, 255, 255, 0.12); }
.top-settings.is-active { background: var(--gold); border-color: var(--gold); color: var(--navy-deep); }
.top-settings.is-active:hover { background: var(--gold-hover); border-color: var(--gold-hover); }
.topbar .top-signout { min-height: 64px; font-size: calc(19px * var(--u, 1)); }
/* js/main.js fitHeader: when the brand and the button cannot share the line. */
.topbar.is-tight .brand-name { font-size: 22px; }
.topbar.is-tight .top-settings { gap: 6px; padding: 0 10px; font-size: 19px; }
.topbar.is-tighter .brand-name { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

.badge {
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  background: var(--surface);
  color: var(--navy);
  font-size: 0.8rem;
  font-weight: 700;
}

.skip-link {
  position: absolute;
  top: 0;
  left: -9999px;
  z-index: 20;
  padding: 0.8rem 1.2rem;
  background: var(--gold);
  color: var(--navy-deep);
  font-weight: 700;
}
.skip-link:focus { top: 1rem; left: 1rem; }

/* ------------------------------------------------------- page frame -- */

.main { max-width: 1280px; margin: 0 auto; padding: 1.25rem 1.5rem 2rem; }

.footer { max-width: 1280px; margin: 0 auto; padding: 0 1.5rem 2rem; color: var(--muted); font-size: 0.85rem; }
.footer a { color: var(--navy); }

.card {
  margin-bottom: 1.25rem;
  padding: 1.5rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 18px;
}
.card.narrow { max-width: 760px; margin: 1rem auto; }
.card h1 { margin: 0.2rem 0 0.6rem; font-size: 1.75rem; }

.lead { max-width: 60ch; color: var(--muted); font-size: 1.1rem; }
.stack { display: flex; flex-direction: column; gap: 0.25rem; }
.two-col { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2rem; }
.small { color: var(--muted); font-size: 0.85rem; }

.plain-main {
  max-width: 760px;
  margin: 1.5rem auto;
  padding: 1.8rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--round);
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 52px;
  padding: 0.6rem 1.2rem;
  border: 2px solid transparent;
  border-radius: 16px;
  font-weight: 700;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}
/* The canvas's main button: full width, 64px, 22px bold (gold, outline or red). */
.btn-big { width: 100%; min-height: 64px; padding: 10px 18px; font-size: var(--t22); line-height: 1.2; }
.btn-sub { display: block; font-size: 0.85rem; font-weight: 400; }

.btn-navy { background: var(--navy); color: var(--surface); }
.btn-navy:hover { background: var(--navy-deep); }
.btn-gold { background: var(--gold); border-color: var(--gold); color: var(--navy-deep); }
.btn-gold:hover { background: var(--gold-hover); border-color: var(--gold-hover); }
.btn-light { background: var(--surface); color: var(--navy); }
.btn-light-dark { background: var(--surface); color: var(--navy); border-color: var(--navy); }
.btn-light-dark:hover { background: var(--navy-wash); }
.btn-danger { background: var(--scam); color: var(--surface); }
.btn-ok { background: var(--safe); color: var(--surface); }
.btn.chosen { background: var(--navy); color: var(--surface); border-color: var(--navy); }

.small-btn { width: auto; min-height: 44px; margin-left: 0.5rem; padding: 0.35rem 0.9rem; font-size: 0.9rem; }

.btn.disabled { opacity: 0.45; pointer-events: none; }
button[disabled] { opacity: 0.6; cursor: wait; }

.action-row { display: flex; flex-wrap: wrap; gap: 0.75rem; margin: 1rem 0; }
.action-row .btn { flex: 1 1 220px; }
.choice-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.choice-row .btn { flex: 1 1 200px; }
.hero-actions { display: flex; flex-direction: column; gap: 0.9rem; margin: 1.5rem 0; }

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

label { display: block; margin: 0.8rem 0; font-weight: 700; }

input,
select,
textarea {
  display: block;
  width: 100%;
  margin-top: 0.35rem;
  padding: 0.75rem 0.9rem;
  background: var(--surface);
  border: 2px solid var(--field);
  border-radius: 10px;
  font-weight: 400;
}
textarea { resize: vertical; }

fieldset { margin: 0.8rem 0; padding: 0.6rem 1rem 0.8rem; border: 2px solid var(--line); border-radius: var(--round-small); }

.check { display: flex; align-items: center; gap: 0.75rem; min-height: 48px; font-weight: 400; }
/* A radio card (frame 1q): 2px grey border, 14px corners; the chosen one has
   a navy border on the navy wash, and a drawn 28px radio (navy ring, navy
   dot) instead of the browser's. Words: .choice-name (22px bold) and
   .choice-sub (19px) in the new screens; the older <strong> + <br> markup
   reads the same. */
.choice {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  min-height: 64px;
  margin: 0.7rem 0;
  padding: 12px 14px;
  background: var(--surface);
  border: 2px solid var(--line);
  border-radius: 14px;
  font-weight: 400;
  cursor: pointer;
}
.choice:has(input:checked) { background: var(--navy-wash); border-color: var(--navy); }
.choice strong,
.choice-name { font-size: var(--t22); font-weight: 700; line-height: 1.25; }
.choice-text { display: flex; flex-direction: column; gap: 2px; }
.choice-sub { font-size: 1rem; line-height: 1.35; }
.check input,
.choice input {
  display: inline-block;
  flex: none;
  width: 26px;
  height: 26px;
  margin: 0.1rem 0 0;
  accent-color: var(--navy);
}
.choice input[type="radio"] {
  appearance: none;
  width: 28px;
  height: 28px;
  margin: 2px 0 0;
  padding: 0;
  background: var(--surface);
  border: 3px solid var(--navy);
  border-radius: 50%;
  cursor: pointer;
}
.choice input[type="radio"]:checked { background: var(--navy); box-shadow: inset 0 0 0 5px var(--navy-wash); }

.paste-box { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.paste-box summary { padding: 0.6rem 0; font-weight: 700; font-size: 1.05rem; cursor: pointer; }

/* ---------------------------------------------------- inbox + reader -- */

.layout { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 1.5rem; }

.inbox-pane,
.reader-pane {
  min-width: 0;
  padding: 1.25rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--round);
}
.inbox-pane { flex: 1 1 360px; }
.reader-pane { flex: 999 1 560px; padding: 1.75rem; }

.pane-head h1 { margin: 0.1rem 0; font-size: 1.75rem; }
.pane-head p { margin: 0.3rem 0 1rem; color: var(--muted); }

.sync-line { margin: 0 0 0.9rem; color: var(--muted); font-size: 0.9rem; }

.box-tabs { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-bottom: 0.75rem; padding-bottom: 0.75rem; border-bottom: 1px solid var(--line); }
.tab {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.35rem 1rem;
  border-radius: 999px;
  color: var(--navy);
  font-weight: 700;
  text-decoration: none;
}
.tab:hover { background: var(--navy-wash); }
.tab.active { background: var(--navy); color: var(--surface); }

.email-list { display: flex; flex-direction: column; margin: 0; padding: 0; list-style: none; }
.email-list > li + li { border-top: 1px solid var(--line); }

.email-item {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  width: 100%;
  padding: 0.85rem 1rem;
  background: transparent;
  border: 0;
  border-radius: var(--round-small);
  color: var(--ink);
  text-align: left;
  cursor: pointer;
}
.email-item span { display: block; }
.email-item .pill { display: inline-block; width: auto; }
.email-item:hover { background: #f5f7fa; }
.email-item[aria-current="true"],
.email-item[aria-selected="true"] { background: var(--navy-wash); box-shadow: inset 6px 0 0 var(--navy); }
.email-from { margin: 0; font-weight: 700; }
.email-subject { margin: 0; font-size: 0.95rem; }
.email-item.unread .email-subject { font-weight: 700; }
.email-date { margin: 0; color: var(--muted); font-size: 0.8rem; }

.pill {
  display: inline-block;
  align-self: flex-start;
  margin-top: 0.35rem;
  padding: 0.1rem 0.7rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--ground);
  color: var(--navy);
  font-size: 0.8rem;
  font-weight: 700;
}
.pill.danger { background: var(--scam); color: var(--surface); }
.pill.caution { background: var(--careful-wash); color: var(--careful); border-color: var(--careful); }
.pill.ok { background: var(--safe-wash); color: var(--safe); }

.empty-big { font-size: 1.5rem; font-weight: 700; }
.reassure { padding: 1rem 1.1rem; border-radius: var(--round-small); background: var(--safe-wash); color: var(--safe-ink); font-weight: 700; }

.mail-meta { margin: 0 0 0.2rem; color: var(--muted); font-size: 0.9rem; overflow-wrap: anywhere; }
#mailSubject { margin: 0.25rem 0 1rem; font-size: 1.5rem; }
#backToList { margin-bottom: 1rem; }
.reader-pane h3 { margin: 1.25rem 0 0.5rem; font-size: 1.2rem; }

.mail-body {
  padding: 1rem 1.1rem;
  background: #f7f9fb;
  border: 1px solid var(--line);
  border-radius: var(--round-small);
  font-family: var(--type);
  font-size: 0.95rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.link-list li { margin: 0.5rem 0; overflow-wrap: anywhere; }

/* ----------------------------------------------------------- verdict -- */

.verdict {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  margin: 1rem 0;
  padding: 1.4rem 1.5rem;
  border: 3px solid;
  border-radius: var(--round);
}
.verdict h3 { margin: 0; font-size: 1.75rem; line-height: 1.15; }
.verdict p { margin: 0; font-size: 1.05rem; }
.verdict .next-step,
.next-step { font-size: 1.2rem; font-weight: 700; }
.verdict .score,
.score { font-size: 0.95rem; }

.verdict.danger { background: var(--scam-wash); border-color: var(--scam); color: var(--scam-ink); }
.verdict.caution { background: var(--careful-wash); border-color: var(--careful); color: var(--careful-ink); }
.verdict.ok { background: var(--safe-wash); border-color: var(--safe); color: var(--safe-ink); }

.why-list { display: flex; flex-direction: column; gap: 0.5rem; margin: 0; padding: 0; list-style: none; }
.why-list li,
.steps-list li { padding: 0.7rem 0.9rem; background: var(--surface); border: 1px solid var(--line); border-radius: var(--round-small); }

.note { padding: 0.8rem 1rem; background: var(--ground); border: 1px solid var(--line); border-radius: var(--round-small); }
.verdict-line { font-weight: 700; }

/* ------------------------------------------- trusted person + answers -- */

.trusted { margin: 1rem 0; padding: 1.1rem; background: #f4f8fc; border: 2px solid var(--navy); border-radius: 14px; }

.shared-card { margin: 1rem 0; padding: 1rem 1.2rem; background: var(--surface); border: 2px dashed var(--navy); border-radius: 14px; }
.shared-card.alert-card { border-style: solid; }

.answer { margin: 0.6rem 0; padding: 1rem 1.2rem; border: 3px solid; border-radius: 14px; font-size: 1.2rem; font-weight: 700; }
.answer.danger { background: var(--scam-wash); border-color: var(--scam); color: var(--scam-ink); }
.answer.ok { background: var(--safe-wash); border-color: var(--safe); color: var(--safe-ink); }
.answer.info,
.answer.waiting { background: var(--navy-wash); border-color: var(--navy); color: var(--navy); }
.answer-form { display: flex; flex-direction: column; gap: 0.9rem; margin: 1.5rem 0; }
.preselected { outline: 4px solid var(--focus-ring); outline-offset: 3px; }

.banner { padding: 1rem 1.2rem; border: 2px solid; border-radius: 14px; font-weight: 700; }
.banner p { margin: 0 0 0.6rem; }
.banner.danger { background: var(--scam-wash); border-color: var(--scam); color: var(--scam-ink); }
.banner.caution { background: var(--careful-wash); border-color: var(--careful); color: var(--careful-ink); }

.toast {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  z-index: 10;
  max-width: min(92vw, 640px);
  padding: 1rem 1.4rem;
  transform: translateX(-50%);
  border-radius: 14px;
  background: var(--navy);
  color: var(--surface);
  font-size: 1.05rem;
  font-weight: 700;
  box-shadow: 0 8px 28px rgba(15, 29, 47, 0.28);
}
.toast.danger { background: var(--scam); }
.toast.ok { background: var(--safe); }

/* ------------------------------------------------- other app screens -- */

.hero {
  max-width: 860px;
  margin: 2rem auto;
  padding: 2.2rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 20px;
}
.hero h1 { margin: 0.2rem 0 1rem; font-size: 2.4rem; line-height: 1.1; }
.promises li { margin: 0.5rem 0; }

.people li,
.known li,
.history li { margin: 0.6rem 0; overflow-wrap: anywhere; }

.pair { display: flex; flex-wrap: wrap; align-items: center; gap: 1.5rem; margin-top: 1rem; }
.qr svg { width: 220px; height: 220px; background: var(--surface); }
.code { margin: 0.3rem 0; font-family: "Courier New", monospace; font-size: 2.4rem; font-weight: 700; letter-spacing: 0.2em; }
.danger-zone { border-color: var(--scam); }

/* ------------------------------------- V2: mobile first, one at a time -- */
/* The senior's screens are one phone-width column, also on a computer. */

.v2-app .main { max-width: 560px; padding: 20px 16px 24px; }
.v2-app .footer { max-width: 560px; padding: 0 16px 24px; font-size: 1rem; }
/* The page ends above the tab bar (--tabbar-h: its measured height, 0 when hidden). */
.has-tabbar .footer { padding-bottom: calc(var(--tabbar-h, 80px) + 24px); }
.v2-app .two-col { grid-template-columns: minmax(0, 1fr); }

.v2 { display: flex; flex-direction: column; gap: 1.1rem; }
.v2 p { margin: 0; }
.v2-wait { color: var(--muted); }
.v2-hello { margin: 0.3rem 0 0; font-size: 1.6rem; }
.v2-demo { padding: 0.6rem 0.9rem; border-radius: var(--round-small); background: var(--navy-wash); color: var(--navy); font-size: 1rem; font-weight: 700; }

.v2-status {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 1.3rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 22px;
}
.v2-status.ok { background: var(--safe-wash); border: 3px solid var(--safe); color: var(--safe-ink); }
.v2-status-big { font-size: 1.6rem; font-weight: 700; line-height: 1.15; }

.v2-big { width: 100%; min-height: 72px; border-radius: 18px; font-size: 1.15rem; }
.v2-line { display: flex; align-items: center; gap: 0.7rem; color: var(--muted); font-size: 0.95rem; }
.v2-avatar { flex: 0 0 44px; height: 44px; display: grid; place-items: center; border-radius: 50%; background: var(--navy); color: var(--gold); font-weight: 700; }

/* Back · count · Listen on one row; at the larger text sizes (and in
   French) Listen moves to its own row on the right instead of spilling. */
.v2-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem; }
.v2-head .v2-read { margin-left: auto; }
.v2-back {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  min-height: 48px;
  padding: 0;
  background: none;
  border: 0;
  color: var(--navy);
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
}
.v2-count { flex: none; color: var(--muted); font-weight: 700; white-space: nowrap; }
/* Read aloud: the word next to the icon, so it is never a guess. */
.v2-read {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  min-height: 48px;
  padding: 0 0.7rem;
  background: var(--surface);
  border: 2px solid var(--navy);
  border-radius: 999px;
  color: var(--navy);
  font: inherit;
  font-size: 0.95rem;
  font-weight: 700;
  white-space: nowrap;
  flex: none;
  cursor: pointer;
}
.v2 .small { font-size: 1rem; }
.v2-voice { display: flex; flex-direction: column; gap: 0.7rem; padding: 1.1rem; background: var(--surface); border: 1px solid var(--line); border-radius: 22px; }
.v2-voice-title { display: flex; align-items: center; gap: 0.5rem; margin: 0; font-size: 1.15rem; }
.v2 audio { width: 100%; }
/* The language switch is for the demo and for testing: on a phone it is a
   small "FR"/"EN" next to the brand, not a second headline. */
.lang-short { display: none; }
@media (max-width: 700px) {
  .v2-app .lang-btn { min-width: 48px; padding: 0 0.8rem; }
  .v2-app .lang-long { display: none; }
  .v2-app .lang-short { display: inline; }
}
.v2 .shared-card { border-style: solid; }
.v2-round {
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  background: var(--surface);
  border: 2px solid var(--navy);
  border-radius: 50%;
  color: var(--navy);
  cursor: pointer;
}

/* A small stack of cards behind the current one says "one of several". */
.v2-stack { position: relative; padding-bottom: 12px; }
.v2-stack::before,
.v2-stack::after {
  content: "";
  position: absolute;
  z-index: 0;
  background: var(--surface);
  border: 2px solid var(--line);
  border-radius: 26px;
}
.v2-stack::before { inset: 16px 14px 0; }
.v2-stack::after { inset: 8px 7px 6px; }

.v2-card {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  padding: 1.4rem 1.3rem;
  background: var(--surface);
  border: 4px solid var(--line);
  border-radius: 26px;
  box-shadow: 0 10px 28px rgba(15, 29, 47, 0.16);
  touch-action: pan-y;
  transition: transform 0.15s ease-out;
}
.v2-card.danger { border-color: var(--scam); }
.v2-card.caution { border-color: var(--careful); }
.v2-card.ok { border-color: var(--safe); }

/* The verdict word stays big, but never wider than the phone at Largest. */
.v2-badge { display: flex; flex-wrap: wrap; align-items: center; gap: 0.7rem; font-size: min(2rem, 11vw); font-weight: 700; line-height: 1.05; }
.v2-card.danger .v2-badge { color: var(--scam); }
.v2-card.caution .v2-badge { color: var(--careful); }
.v2-card.ok .v2-badge { color: var(--safe); }
.v2-badge-dot { flex: none; width: 60px; height: 60px; display: grid; place-items: center; border-radius: 50%; }
.v2-card.danger .v2-badge-dot { background: var(--scam); color: var(--surface); }
.v2-card.caution .v2-badge-dot { background: var(--careful-wash); border: 3px solid var(--careful); color: var(--careful); }
.v2-card.ok .v2-badge-dot { background: var(--safe-wash); border: 3px solid var(--safe); color: var(--safe); }

.v2-headline { margin: 0; font-size: 1.3rem; line-height: 1.25; }
.v2-fact { font-size: 1.1rem; }
.v2-fact-box { padding: 0.7rem 0.8rem; border-radius: 14px; background: var(--ground); }
.v2-card.danger .v2-fact-box { background: var(--scam-wash); }
.v2-card.caution .v2-fact-box { background: var(--careful-wash); }
/* Under a reason: what it was checked against, in plain words. Its own
   line below the text, so it never hides at the end of a sentence; 16 px
   at the normal size, and it wraps at the largest size instead of
   overflowing. Navy on the navy wash reads at better than AAA contrast. */
.v2-chip {
  display: block;
  width: fit-content;
  max-width: 100%;
  margin-top: 0.4rem;
  padding: 0.15rem 0.7rem;
  background: var(--navy-wash);
  border: 1.5px solid var(--navy);
  border-radius: 999px;
  color: var(--navy);
  font-size: 0.85rem;
  font-weight: 700;
  line-height: 1.35;
}
.v2-next { font-size: 1.1rem; font-weight: 700; }
.v2-more { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.v2-more .btn { min-height: 48px; font-size: 0.95rem; }

/* The two answers sit in a bar fixed to the bottom of the screen, outside
   the card, so they stay in reach without covering what the card says. */
.v2-actions {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 14;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
  max-width: calc(560px + 2rem);
  margin: 0 auto;
  padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom));
  background: var(--surface);
  border-top: 1px solid var(--line);
  box-shadow: 0 -8px 24px rgba(15, 29, 47, 0.12);
}
/* --tabbar-h is the tab bar's measured height (js/main.js): labels may wrap. */
.has-tabbar .v2-actions { bottom: var(--tabbar-h, calc(80px + env(safe-area-inset-bottom))); padding-bottom: 0.75rem; }
.v2-action { flex-direction: column; gap: 0.3rem; min-height: 88px; border-radius: 20px; font-size: 1.05rem; }
.v2-hint { display: flex; align-items: center; justify-content: center; gap: 0.4rem; color: var(--muted); font-size: 1rem; text-align: center; }
.v2-quiet { width: 100%; }
.v2-link {
  align-self: center;
  min-height: 44px;
  background: none;
  border: 0;
  color: var(--navy);
  font-size: 0.95rem;
  text-decoration: underline;
  text-underline-offset: 4px;
  cursor: pointer;
}

.v2-done-note { display: flex; flex-direction: column; gap: 0.6rem; padding: 1.1rem; border-radius: 20px; background: var(--navy); color: var(--surface); }
.v2-done-title { display: flex; align-items: center; gap: 0.5rem; font-size: 1.15rem; font-weight: 700; }
.v2-done-title svg { color: var(--gold); }
.v2-undo { align-self: flex-start; min-height: 56px; background: transparent; border-color: var(--surface); color: var(--surface); }
.v2-all-done { display: flex; flex-direction: column; align-items: center; gap: 0.7rem; padding: 1.5rem 0; text-align: center; }
.v2-all-done h1 { margin: 0; font-size: 1.8rem; }
.v2-big-check { width: 120px; height: 120px; display: grid; place-items: center; border-radius: 50%; background: var(--safe-wash); border: 4px solid var(--safe); color: var(--safe); }
.v2-text-ready { display: flex; flex-direction: column; gap: 0.7rem; }

/* PrudenceTabs: the bottom tab bar on phones (four tabs for the senior, two
   in the demo); on a computer the top links do the same job. Each tab is as
   wide as its word (flex 1 1 auto, one line), not a quarter, so French
   "Aujourd'hui" and "Bloqués" stay whole (frame 1d). 80px tall, a 28px icon
   over a 19px x --u bold label; the current tab is navy with a 4px gold line
   on top, the others #4a4a4a. Where the words cannot fit (js/main.js
   fitTabbar), .is-tight drops the labels to 19px, then .is-wrap lets one
   break rather than spill. */
.tabbar {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 15;
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  padding: 0 4px env(safe-area-inset-bottom);
  background: var(--surface);
  border-top: 1px solid var(--line);
}
.tabbar a {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 80px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 6px 4px 8px;
  color: var(--muted);
  font-size: calc(19px * var(--u, 1));
  font-weight: 700;
  line-height: 1.15;
  white-space: nowrap;
  text-align: center;
  text-decoration: none;
}
.tabbar svg { flex: none; }
.tabbar a[aria-current="page"] { color: var(--navy); box-shadow: inset 0 4px 0 var(--gold); }
.tabbar.is-tight a { font-size: 19px; }
.tabbar.is-wrap a { white-space: normal; }
.tabbar.is-wrap span { max-width: 100%; overflow-wrap: anywhere; }

@media (min-width: 701px) {
  .tabbar { display: none !important; }
  .has-tabbar .v2-actions { bottom: 0; padding-bottom: calc(0.75rem + env(safe-area-inset-bottom)); }
  .v2-actions { border: 1px solid var(--line); border-bottom: 0; border-radius: 20px 20px 0 0; }
}
@media (max-width: 700px) {
  /* On a phone the senior's header is the brand and the Settings button, on one line. */
  .v2-app .nav-tabbed,
  .v2-app .brand-sub { display: none; }
  .v2-app .topbar { flex-wrap: nowrap; }
  /* FR / EN (signed out, demo) in the bar: readable, but the bar never spills at Largest. */
  .v2-app .topbar .btn { min-height: 48px; padding: 0 0.8rem; font-size: min(1rem, 4.6vw); }
}
/* While the answer bar is up, the page ends above it (and above the tabs). */
/* --dock-h is the bar's measured height (labels may wrap to two lines). */
.v2-docked .footer { padding-bottom: calc(var(--dock-h, 150px) + 1.5rem); }
.v2-docked.has-tabbar .footer { padding-bottom: calc(var(--dock-h, 150px) + var(--tabbar-h, calc(80px + env(safe-area-inset-bottom))) + 1.5rem); }
@media (min-width: 701px) { .v2-docked.has-tabbar .footer { padding-bottom: calc(var(--dock-h, 150px) + 1.5rem); } }

/* ------------------------------------------------- narrow + a11y bits -- */

@media (max-width: 900px) {
  .main { padding: 1rem; }
  .reader-pane { padding: 1.25rem; }
  .two-col { grid-template-columns: minmax(0, 1fr); }
  .hero h1 { font-size: 2rem; }
  .verdict h3 { font-size: 1.5rem; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

[tabindex="-1"]:focus:not(:focus-visible),
h1[tabindex="-1"]:focus,
h2[tabindex="-1"]:focus { outline: none; box-shadow: none; }

[hidden] { display: none !important; }

/* ------------------------------------------------------------ learn -- */
/* The Learn tab (_product/specs/micro-learning.md; the 2026-11-04 canvas,
   frames 1o and 1p; the spec's "Thread screen"): the home, then a lesson as
   one thread, in the same column and under the same header as Today. Stars
   are drawn in SVG (navy outline, gold fill, always next to words or with a
   label): gold is never text on white. The home's progress card and badge
   circles are in "redesign: learn" at the end of this file. */

.learn-hello { display: flex; flex-direction: column; gap: 4px; }
.learn-lead { color: var(--muted); }

.learn-progress { display: flex; flex-direction: column; gap: 14px; padding: 20px; background: var(--surface); border: 1px solid var(--line); border-radius: 22px; }
.learn-progress-line { min-width: 0; }
.learn-progress-line span { white-space: nowrap; }
.learn-badges-box { display: flex; flex-direction: column; gap: 8px; }

.learn-group { display: flex; flex-direction: column; gap: 16px; }
.learn-group .section-title { margin-top: 4px; }
.learn-list { display: flex; flex-direction: column; gap: 16px; margin: 0; padding: 0; list-style: none; }

/* A lesson is one whole-card link: a row (2px line, 18px corners), the
   first one to try the big card (4px navy, 26px corners, the shadow). */
.learn-lesson {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 64px;
  padding: 16px;
  background: var(--surface);
  border: 2px solid var(--line);
  border-radius: 18px;
  color: var(--ink);
  text-decoration: none;
}
.learn-lesson:hover { border-color: var(--navy); }
.learn-lesson-top { display: flex; align-items: center; gap: 14px; }
.learn-lesson-body { display: flex; flex: 1; flex-direction: column; gap: 6px; min-width: 0; }
.learn-lesson-title { font-size: var(--t22); font-weight: 700; line-height: 1.25; overflow-wrap: anywhere; }
.learn-emoji { flex: none; width: 48px; height: 48px; display: grid; place-items: center; border-radius: 50%; background: var(--navy-wash); font-size: 24px; line-height: 1; }
.learn-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; color: var(--muted); font-size: var(--t19); line-height: 1.3; }
.learn-cue { display: inline-flex; align-items: center; gap: 4px; color: var(--navy); font-weight: 700; }
.learn-lesson.is-next { flex-direction: column; align-items: stretch; gap: 14px; padding: 20px; border: 4px solid var(--navy); border-radius: 26px; box-shadow: 0 10px 28px rgba(15, 29, 47, 0.16); }
.learn-lesson.is-next .learn-lesson-body { gap: 4px; }
.learn-lesson.is-next .learn-emoji { width: 64px; height: 64px; font-size: 32px; }
.learn-lesson.is-next .learn-lesson-title { font-size: var(--t26); line-height: 1.2; }
.learn-start { display: flex; align-items: center; justify-content: center; gap: 10px; min-height: 64px; padding: 10px 18px; border-radius: 16px; background: var(--gold); color: var(--navy-deep); font-size: var(--t22); font-weight: 700; line-height: 1.2; }
.learn-lesson.is-next:hover .learn-start { background: var(--gold-hover); }
.learn-lesson.is-done { align-items: flex-start; }
.learn-stars { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; color: var(--muted); font-size: var(--t19); line-height: 1.3; }
.learn-star-row { display: inline-flex; flex: none; gap: 3px; }
.learn-done { display: inline-flex; align-items: center; gap: 0.2rem; padding: 0 0.55rem 0 0.4rem; border-radius: 999px; background: var(--safe-wash); color: var(--safe-ink); font-weight: 700; }
.learn-done svg { color: var(--safe); }

.learn-star-icon { flex: none; fill: var(--surface); stroke: var(--navy); }
.learn-star-icon.is-on { fill: var(--gold); }

/* "Choice 1 of 3" and the three stars of the lesson. */
.learn-stepper { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 10px; }
.learn-step-label { color: var(--navy); font-size: var(--t22); font-weight: 700; line-height: 1.25; }
.learn-step-stars { display: inline-flex; gap: 8px; }
.learn-star { display: grid; place-items: center; width: 34px; height: 38px; }
.learn-star.is-current { box-shadow: inset 0 -3px 0 var(--gold); }
.learn-star.is-new .learn-star-icon { filter: drop-shadow(0 0 5px rgba(233, 168, 32, 0.75)); animation: learn-pop 0.6s ease-out both; }
@keyframes learn-pop { 0% { transform: scale(0.3); } 60% { transform: scale(1.3); } 100% { transform: scale(1); } }

/* The lesson (the spec's Design, "Thread screen", 2026-11-04 evening): the
   lesson's emoji and title once, then the conversation, one list of
   messages that grows downward like texts with a friend. What the thread
   scrolls into view (a new message, the buttons) stops 16px above the tab
   bar (--tabbar-h, 0 without one), so its last button is never under it. */
.learn-lesson-head { display: flex; align-items: center; gap: 14px; }
.learn-lesson-head h1 { margin: 0; font-size: var(--t26); line-height: 1.25; overflow-wrap: anywhere; }
.learn-lesson-head .learn-emoji { width: 56px; height: 56px; background: var(--surface); border: 2px solid var(--line); font-size: 28px; }
.learn-thread { display: flex; flex-direction: column; gap: 18px; margin: 0; padding: 0; list-style: none; }
.learn-thread > li,
.learn-run > .learn-choices,
.learn-thread-end { scroll-margin: 16px 0 calc(var(--tabbar-h, 0px) + 16px); }

/* A message names its speaker above its bubble: Prudence's gold mark and
   name, the character's emoji and the name he borrows, or "You". Prudence's
   bubble is white and the character's grey, both on the left; the person's
   is navy, on the right. One bubble per message, its lines as paragraphs. */
.learn-msg { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.learn-msg.is-you { align-items: flex-end; }
.learn-msg-name { display: flex; align-items: center; gap: 10px; color: var(--muted); font-size: var(--t19); font-weight: 700; line-height: 1.25; overflow-wrap: anywhere; }
.learn-msg-name > span { min-width: 0; }
.learn-mark { flex: none; width: 32px; height: 32px; display: grid; place-items: center; border-radius: 50%; background: var(--gold); color: var(--navy-deep); }
.learn-avatar { flex: none; width: 40px; height: 40px; display: grid; place-items: center; border-radius: 50%; background: var(--surface); border: 2px solid var(--line); font-size: 22px; line-height: 1; }
.learn-bubble { display: flex; flex-direction: column; gap: 10px; max-width: 88%; padding: 14px 18px; border-radius: 6px 22px 22px; background: var(--line); color: var(--ink); font-size: var(--t22); line-height: 1.45; overflow-wrap: anywhere; }
.learn-msg.is-prudence .learn-bubble { background: var(--surface); border: 1px solid var(--line); }
.learn-msg.is-you .learn-bubble { border-radius: 22px 6px 22px 22px; background: var(--navy); color: var(--surface); }
/* Prudence's tell after a choice, what gave him away: her bubble in gold,
   the bulb before her line. */
.learn-msg.is-tell .learn-bubble { flex-direction: row; align-items: flex-start; background: var(--gold-wash); border: 2px solid var(--gold); }
.learn-msg.is-tell .learn-bubble > svg { flex: none; margin-top: calc((1.45em - 26px) / 2); color: var(--navy); }
.learn-msg.is-tell .learn-bubble > p { min-width: 0; }

/* The question is a heading in the thread, a little apart from the
   messages above it. Its choices, a chat's replies, Rewind and Next are the
   big buttons at the end of the thread, never docked: full width, stacked,
   and they wrap. */
.learn-ask { padding-top: 6px; }
.learn-question { margin: 0; font-size: var(--t26); line-height: 1.25; overflow-wrap: anywhere; }
.learn-choices { display: flex; flex-direction: column; gap: 0.75rem; }
.learn-choice {
  display: flex;
  justify-content: flex-start;
  gap: 0.7rem;
  width: 100%;
  min-height: 64px;
  padding: 0.8rem 1.1rem;
  background: var(--surface);
  border-color: var(--navy);
  color: var(--navy);
  font-size: var(--t22);
  line-height: 1.35;
  text-align: left;
}
.learn-choice:hover { background: var(--navy-wash); }
.learn-choice svg { flex: none; }
.learn-choice span { min-width: 0; overflow-wrap: anywhere; }
/* A choice already tried, when Rewind brings the question back: grey with
   "Tried" in words under it, nothing on tap (aria-disabled: still reached by
   the keyboard and read by a screen reader); never red. */
.learn-choice.is-tried,
.learn-choice.is-tried:hover { background: var(--soon); border-color: var(--field); color: var(--muted); cursor: default; }
.learn-choice-words { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.learn-tried { padding: 0 12px; border: 2px solid var(--field); border-radius: 999px; background: var(--surface); font-size: var(--t19); line-height: 1.5; white-space: nowrap; }

.learn-thread-end { display: flex; flex-direction: column; }

/* The cheer after a right choice: a small note in the middle of the
   thread, gold-rimmed, "Well spotted!" over "You earned a star." with the
   star popping in the first time (the check otherwise). */
.learn-cheer { align-self: center; display: flex; align-items: center; gap: 10px; max-width: 100%; padding: 8px 18px 8px 8px; border: 2px solid var(--gold); border-radius: 20px; background: var(--gold-wash); color: var(--navy-deep); font-size: var(--t19); line-height: 1.35; }
.learn-cheer > p { display: flex; flex-direction: column; min-width: 0; overflow-wrap: anywhere; }
.learn-cheer strong { color: var(--navy); font-size: var(--t22); }
.learn-cheer-dot { flex: none; width: 48px; height: 48px; display: grid; place-items: center; border-radius: 50%; background: var(--surface); color: var(--navy); }
.learn-cheer-dot .learn-star-icon { animation: learn-pop 0.6s ease-out 0.15s both; }

/* Each new message and the buttons rise into place; what a Rewind takes
   back fades and slides to the left, the way the rewind arrows point (never
   past the right edge of the screen), for 320ms (LEAVE in learn.js), then
   goes. Both are off under reduced motion (below the confetti), where
   learn.js does not wait either. */
.learn-thread > li,
.learn-run > .learn-choices,
.learn-thread-end { animation: learn-in 0.3s ease-out both; }
.learn-thread > li.is-leaving { animation: learn-out 0.32s ease-in both; }
@keyframes learn-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes learn-out { to { opacity: 0; transform: translateX(-32px); } }

/* The end of a lesson: the stars, the badge the first time, the rule. */
.learn-end { display: flex; flex-direction: column; align-items: center; gap: 0.5rem; text-align: center; }
.learn-end h1 { margin: 0; font-size: 1.8rem; }
.learn-end-stars { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.6rem; color: var(--navy); font-size: 1.15rem; font-weight: 700; }
.learn-end-row { display: inline-flex; gap: 0.35rem; }
.learn-new-badge { display: flex; align-items: center; gap: 0.8rem; margin-top: 0.4rem; padding: 0.75rem 1.1rem; background: var(--gold-wash); border: 2px solid var(--gold); border-radius: 18px; text-align: left; }
.learn-new-badge-emoji { font-size: 2.2rem; line-height: 1; }
.learn-new-badge-words { display: flex; flex-direction: column; }
.learn-new-badge-label { color: var(--muted); font-weight: 700; }
.learn-new-badge-name { color: var(--navy-deep); font-size: 1.15rem; font-weight: 700; line-height: 1.3; }
.learn-rule { display: flex; flex-direction: column; gap: 0.6rem; padding: 1.1rem; border-radius: 20px; background: var(--navy); color: var(--surface); }
.learn-rule h2 { display: flex; align-items: center; gap: 0.4rem; margin: 0; color: var(--gold); font-size: 1rem; line-height: 1.2; }
.learn-rule-text { font-size: 1.3rem; font-weight: 700; line-height: 1.3; }
.learn-end-actions { display: flex; flex-direction: column; gap: 0.75rem; }
.learn-end-actions .btn-link { align-self: center; }

/* "Try it on a real one": the example message, then the real verdict. */
.learn-real-note { color: var(--muted); }
.learn-real-msg { display: flex; flex-direction: column; align-items: flex-start; gap: 0.5rem; padding: 1rem 1.1rem; background: var(--surface); border: 2px solid var(--line); border-radius: 18px; }
.learn-real-from { display: flex; align-items: center; gap: 0.4rem; color: var(--muted); font-weight: 700; overflow-wrap: anywhere; }
.learn-real-from svg { flex: none; }
.learn-real-subject { font-weight: 700; overflow-wrap: anywhere; }
.learn-real-body { font-size: 1.1rem; overflow-wrap: anywhere; }
.learn-real-msg .mail-body { width: 100%; margin: 0; }

/* Confetti: CSS only, falls once for about 1.2 s and ends invisible; the
   pieces are placed by class (no style attributes under the CSP). */
.learn-confetti { position: fixed; inset: 0; z-index: 30; overflow: hidden; pointer-events: none; }
.learn-confetti i { position: absolute; width: 8px; height: 14px; border-radius: 2px; background: var(--gold); animation: learn-fall 1.2s cubic-bezier(0.25, 0.6, 0.55, 1) both; }
.learn-confetti i:nth-child(3n) { width: 9px; height: 9px; border-radius: 50%; }
.learn-confetti i:nth-child(5n+2) { background: var(--navy); }
.learn-confetti i:nth-child(5n+3) { background: var(--safe); }
.learn-confetti i:nth-child(5n+4) { background: var(--focus-ring); }
.learn-confetti i:nth-child(5n) { background: var(--gold-hover); }
.learn-confetti.is-big i { --fall: 62vh; }
@keyframes learn-fall {
  from { transform: translateY(0) rotate(0deg); opacity: 1; }
  75% { opacity: 1; }
  to { transform: translateY(var(--fall, 46vh)) rotate(var(--turn, 200deg)); opacity: 0; }
}
.learn-confetti .lc-1 { left: 37%; top: 9%; --turn: 254deg; animation-delay: .19s; }
.learn-confetti .lc-2 { left: 74%; top: 14%; --turn: -276deg; animation-delay: .07s; }
.learn-confetti .lc-3 { left: 15%; top: 23%; --turn: 173deg; animation-delay: .12s; }
.learn-confetti .lc-4 { left: 52%; top: 13%; --turn: 411deg; animation-delay: .20s; }
.learn-confetti .lc-5 { left: 89%; top: 34%; --turn: -231deg; animation-delay: .17s; }
.learn-confetti .lc-6 { left: 29%; top: 17%; --turn: -211deg; animation-delay: .07s; }
.learn-confetti .lc-7 { left: 66%; top: 23%; --turn: 259deg; animation-delay: .13s; }
.learn-confetti .lc-8 { left: 5%; top: 28%; --turn: -241deg; animation-delay: .14s; }
.learn-confetti .lc-9 { left: 43%; top: 26%; --turn: 206deg; animation-delay: .11s; }
.learn-confetti .lc-10 { left: 81%; top: 24%; --turn: -155deg; animation-delay: .16s; }
.learn-confetti .lc-11 { left: 19%; top: 23%; --turn: -256deg; animation-delay: .04s; }
.learn-confetti .lc-12 { left: 58%; top: 11%; --turn: 241deg; animation-delay: .07s; }
.learn-confetti .lc-13 { left: 94%; top: 20%; --turn: -306deg; animation-delay: .03s; }
.learn-confetti .lc-14 { left: 35%; top: 33%; --turn: 257deg; animation-delay: .00s; }
.learn-confetti .lc-15 { left: 70%; top: 28%; --turn: 279deg; animation-delay: .01s; }
.learn-confetti .lc-16 { left: 12%; top: 23%; --turn: 301deg; animation-delay: .15s; }
.learn-confetti .lc-17 { left: 47%; top: 17%; --turn: 417deg; animation-delay: .05s; }
.learn-confetti .lc-18 { left: 85%; top: 18%; --turn: 139deg; animation-delay: .03s; }
.learn-confetti .lc-19 { left: 25%; top: 9%; --turn: -145deg; animation-delay: .07s; }
.learn-confetti .lc-20 { left: 62%; top: 9%; --turn: 261deg; animation-delay: .10s; }
.learn-confetti .lc-21 { left: 2%; top: 32%; --turn: 155deg; animation-delay: .03s; }
.learn-confetti .lc-22 { left: 39%; top: 10%; --turn: 323deg; animation-delay: .20s; }
.learn-confetti .lc-23 { left: 76%; top: 16%; --turn: 261deg; animation-delay: .14s; }
.learn-confetti .lc-24 { left: 17%; top: 28%; --turn: 407deg; animation-delay: .20s; }
.learn-confetti .lc-25 { left: 53%; top: 8%; --turn: 206deg; animation-delay: .11s; }
.learn-confetti .lc-26 { left: 90%; top: 14%; --turn: 200deg; animation-delay: .09s; }
.learn-confetti .lc-27 { left: 30%; top: 29%; --turn: -366deg; animation-delay: .18s; }
.learn-confetti .lc-28 { left: 68%; top: 12%; --turn: 175deg; animation-delay: .02s; }
.learn-confetti .lc-29 { left: 7%; top: 32%; --turn: -157deg; animation-delay: .09s; }
.learn-confetti .lc-30 { left: 44%; top: 20%; --turn: 413deg; animation-delay: .11s; }
.learn-confetti .lc-31 { left: 81%; top: 28%; --turn: -375deg; animation-delay: .14s; }
.learn-confetti .lc-32 { left: 22%; top: 8%; --turn: -406deg; animation-delay: .03s; }
.learn-confetti .lc-33 { left: 57%; top: 20%; --turn: -361deg; animation-delay: .15s; }
.learn-confetti .lc-34 { left: 96%; top: 7%; --turn: 131deg; animation-delay: .06s; }
.learn-confetti .lc-35 { left: 36%; top: 15%; --turn: -194deg; animation-delay: .20s; }
.learn-confetti .lc-36 { left: 73%; top: 6%; --turn: -201deg; animation-delay: .13s; }
/* With reduced motion: no confetti at all, the star fills without its pop,
   and the thread's messages and buttons appear and go without moving. */
@media (prefers-reduced-motion: reduce) {
  .learn-confetti { display: none; }
  .learn-star.is-new .learn-star-icon,
  .learn-cheer-dot .learn-star-icon,
  .learn-thread > li,
  .learn-thread > li.is-leaving,
  .learn-run > .learn-choices,
  .learn-thread-end { animation: none; }
}

/* --- 2026-11-04 redesign: shared components --- */
/* The pieces the redesigned screens are built from, with the canvas's values
   (_product/design/2026-11-04-redesign/claude-design/Prudence Redesign.dc.html,
   frames 1a to 1s). Sizes in rem through the --t tokens follow the person's
   text size (see "Text sizes" at the top); paddings, corners and icons stay in
   px as on the canvas. Icons: icon(name, size, width) in js/ui.js; the verdict
   pill: verdictPill(verdict) in js/ui.js; "What Prudence protects":
   renderProtects() in js/protects.js. No style attributes: the CSP allows
   only this file.

   Screen frame
     .screen          the column's content: a flex column, 20px between blocks
     .screen.is-snug  16px between blocks (Check, Learn, sub-screens)
     .screen-head     a back link and Listen on one row, Listen to the right
     .screen-title    h1, 32px bold, line-height 1.15
     .screen-lead     the sentence under a title, 22px
     .section-title   h2 inside a screen ("What Prudence protects", "Still
                      unsure?", "Who sent it?"), 22px bold
   Rows (Today, Settings, "What Prudence protects")
     .row-card        white card, 1px #d8dee6 border, 18px corners, 16px
                      padding, 12px between its parts; a .btn inside spans
                      the full width
     .row-head        the 44px icon and the words, 12px apart
     .row-icon        44px navy-wash circle with a navy 24px icon; .is-danger
                      (red on #fef3f2, the "scams moved away" row), .is-grey
                      (Coming soon), .is-text (the "Aa" of Text size)
     .row-text        name over state, 4px apart
     .row-title       name and a pill on one line (Coming soon rows)
     .row-name        22px bold
     .row-state       19px; an icon first (icon("check-circle", 20, 2.5)) is
                      the green "on" mark
     .row-soon        on a .row-card: the flat grey Coming soon row, no
                      border, #4a4a4a words, nothing to tap
     .pill-soon       the "Coming soon" tag: 19px bold, 2px #8a97a8 outline
   Buttons (with .btn)
     .btn-big         the main button: full width, 64px, 22px (with .btn-gold
                      for the one gold verb of a screen)
     .btn-outline     white, 2px navy, navy words, 64px, 22px
     .btn-danger-outline  white, 2px red, red words (Delete my account)
     .btn-choice      a big left-aligned choice, icon then label: 88px, 22px
                      corners, 24px words, navy outline (with .btn-gold:
                      gold); .is-hero 120px with .btn-choice-label and
                      .btn-choice-sub (19px) inside (frame 1g); .is-compact:
                      64px, 16px corners, 22px words (Today, frame 1b; gold
                      is 80px there)
     .btn-link        the underlined text button ("More ways"), 64px tall
     .btn-back        "‹ Today", "‹ Check", "‹ Settings": 22px bold navy, no
                      border, 64px tall; icon("chevron-left", 28, 2.5) first
     .btn-listen      the round-ended "Listen" button: 64px, 19px bold
   Chips (with or without .btn: they are <button>s)
     .chip-row        wrapped chips, 10px apart
     .chip            64px pill, 2px navy outline, 22px bold; .is-on or
                      aria-pressed="true": navy, white words, a drawn tick
                      first (frame 1i)
     .chip-small      56px, 19px words (the My messages filters, frame 1e)
   Verdicts and cards
     .pill-verdict    icon and word in a pill, 19px bold, 999px corners;
                      .is-careful (amber outline), .is-safe (green outline),
                      .is-scam (solid red, white words)
     .hero-card       Today's card: white, 2px navy border, 22px corners,
                      20px padding; .hero-title (28px) and .hero-text (22px)
     .allclear        the green all-clear card (3px green, 22px corners);
                      .allclear-head, .allclear-mark (the 56px white circle
                      with icon("check", 32, 3)), .allclear-title (26px),
                      .allclear-text (19px)
     .soon-button     a verb that is not built yet (frame 1m): flat grey,
                      64px, the label left and .pill-soon right; give it
                      aria-disabled="true", nothing happens on tap
   Lists
     .msg-list        the white list card of My messages (frame 1e); one
                      .msg-row per message: .msg-from (22px bold), .msg-line
                      (19px), a .pill-verdict, the chevron at the right
*/

.screen { display: flex; flex-direction: column; gap: 20px; }
.screen.is-snug { gap: 16px; }
.screen p { margin: 0; }
.screen-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
.screen-title { margin: 0; font-size: var(--t32); font-weight: 700; line-height: 1.15; }
.screen-lead { margin: 0; font-size: var(--t22); line-height: 1.4; }
.section-title { margin: 0 0 2px; font-size: var(--t22); font-weight: 700; line-height: 1.2; }

/* Rows */
.protects { display: flex; flex-direction: column; gap: 10px; }
.row-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 18px;
}
.row-card > .btn { width: 100%; }
.row-card > .choice { margin: 0; }
.row-head { display: flex; align-items: flex-start; gap: 12px; }
.row-head.is-centered { align-items: center; }
.row-icon {
  flex: none;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--navy-wash);
  color: var(--navy);
}
.row-icon.is-danger { background: var(--scam-wash); color: var(--scam); }
.row-icon.is-grey { background: var(--line); color: var(--muted); }
.row-icon.is-text { font-size: 20px; font-weight: 700; line-height: 1; }
.row-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.row-title { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.row-name { font-size: var(--t22); font-weight: 700; line-height: 1.25; overflow-wrap: anywhere; }
.row-state { display: flex; align-items: flex-start; gap: 6px; font-size: var(--t19); line-height: 1.35; }
.row-state > svg { flex: none; margin-top: 0.2em; color: var(--safe); }
.row-soon { flex-direction: row; align-items: flex-start; background: var(--soon); border-color: var(--soon); color: var(--muted); cursor: default; }
.pill-soon {
  display: inline-block;
  padding: 2px 10px;
  border: 2px solid var(--field);
  border-radius: 999px;
  font-size: var(--t19);
  font-weight: 700;
  line-height: 1.2;
  white-space: nowrap;
}

/* Buttons */
.btn-outline { min-height: 64px; padding: 10px 16px; background: var(--surface); border-color: var(--navy); color: var(--navy); font-size: var(--t22); line-height: 1.2; }
.btn-outline:hover { background: var(--navy-wash); }
.btn-danger-outline { min-height: 64px; padding: 10px 16px; background: var(--surface); border-color: var(--scam); color: var(--scam); font-size: var(--t22); line-height: 1.2; }
.btn-danger-outline:hover { background: var(--scam-wash); }
.btn svg { flex: none; }

.btn-choice {
  display: flex;
  justify-content: flex-start;
  gap: 16px;
  width: 100%;
  min-height: 88px;
  padding: 12px 20px;
  background: var(--surface);
  border-color: var(--navy);
  border-radius: 22px;
  color: var(--navy);
  font-size: var(--t24);
  line-height: 1.2;
  text-align: left;
}
.btn-choice:hover { background: var(--navy-wash); }
.btn-choice.btn-gold { background: var(--gold); border-color: var(--gold); color: var(--navy-deep); }
.btn-choice.btn-gold:hover { background: var(--gold-hover); border-color: var(--gold-hover); }
.btn-choice.is-hero { min-height: 120px; padding: 16px 20px; }
.btn-choice-words { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.btn-choice-label { font-size: var(--t24); font-weight: 700; line-height: 1.2; }
.btn-choice-sub { font-size: var(--t19); font-weight: 400; line-height: 1.3; }
.btn-choice.is-compact { gap: 14px; min-height: 64px; padding: 10px 18px; border-radius: 16px; font-size: var(--t22); }
.btn-choice.is-compact.btn-gold { min-height: 80px; padding: 12px 18px; border-radius: 18px; }

.btn-link {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: 6px;
  min-height: 64px;
  padding: 0 8px;
  background: none;
  border: 0;
  color: var(--navy);
  font-size: var(--t19);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 4px;
  cursor: pointer;
}
.btn-back {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: 2px;
  min-height: 64px;
  padding: 0 12px 0 0;
  background: none;
  border: 0;
  color: var(--navy);
  font-size: var(--t22);
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
}
.btn-back:hover { text-decoration: underline; text-underline-offset: 4px; }
.btn-listen {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 64px;
  padding: 0 18px;
  background: var(--surface);
  border: 2px solid var(--navy);
  border-radius: 999px;
  color: var(--navy);
  font-size: var(--t19);
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
}
.btn-listen:hover { background: var(--navy-wash); }

/* Chips */
.chip-row { display: flex; flex-wrap: wrap; gap: 10px; }
.chip-row.is-small { gap: 8px; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 64px;
  padding: 0 20px;
  background: var(--surface);
  border: 2px solid var(--navy);
  border-radius: 999px;
  color: var(--navy);
  font-size: var(--t22);
  font-weight: 700;
  line-height: 1.2;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.chip:hover { background: var(--navy-wash); }
.chip { max-width: 100%; overflow-wrap: anywhere; }
.chip.is-on,
.chip[aria-pressed="true"] { background: var(--navy); color: var(--surface); }
/* The chosen chip's tick, drawn here so a chip is never chosen by colour alone. */
.chip.is-on::before,
.chip[aria-pressed="true"]::before {
  content: "";
  flex: none;
  width: 24px;
  height: 24px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7'/%3E%3C/svg%3E") center / contain no-repeat;
}
.chip-small { min-height: 56px; padding: 0 18px; font-size: var(--t19); }
.chip-small.is-on::before,
.chip-small[aria-pressed="true"]::before { width: 20px; height: 20px; }

/* Verdicts */
.pill-verdict {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: 6px;
  margin-top: 4px;
  padding: 4px 12px 4px 8px;
  border: 2px solid;
  border-radius: 999px;
  font-size: var(--t19);
  font-weight: 700;
  line-height: 1.2;
}
.pill-verdict svg { flex: none; }
.pill-verdict.is-careful { background: var(--careful-wash); border-color: var(--careful); color: var(--careful-ink); }
.pill-verdict.is-careful svg { color: var(--careful); }
.pill-verdict.is-safe { background: var(--safe-wash); border-color: var(--safe); color: var(--safe-ink); }
.pill-verdict.is-safe svg { color: var(--safe); }
.pill-verdict.is-scam { background: var(--scam); border-color: var(--scam); color: var(--surface); }

/* Today's cards */
.hero-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 20px;
  background: var(--surface);
  border: 2px solid var(--navy);
  border-radius: 22px;
}
.hero-title { margin: 0; font-size: var(--t28); font-weight: 700; line-height: 1.2; }
.hero-text { margin: 0; font-size: var(--t22); line-height: 1.4; }
.allclear {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 20px;
  background: var(--safe-wash);
  border: 3px solid var(--safe);
  border-radius: 22px;
  color: var(--safe-ink);
}
.allclear-head { display: flex; align-items: center; gap: 12px; }
.allclear-mark {
  flex: none;
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  background: var(--surface);
  border: 3px solid var(--safe);
  border-radius: 50%;
  color: var(--safe);
}
.allclear-title { margin: 0; font-size: var(--t26); font-weight: 700; line-height: 1.2; }
.allclear-text { margin: 0; font-size: var(--t19); line-height: 1.4; }

/* A verb that is not built yet: grey, flat, the Coming soon tag at the right. */
.soon-button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  min-height: 64px;
  padding: 10px 16px;
  background: var(--soon);
  border: 0;
  border-radius: 16px;
  color: var(--muted);
  font-family: inherit;
  font-size: var(--t22);
  font-weight: 700;
  line-height: 1.2;
  text-align: left;
  cursor: default;
}
.soon-button { flex-wrap: wrap; }
.soon-button > span:first-child { display: inline-flex; align-items: center; gap: 10px; min-width: 0; }
.soon-button svg,
.soon-button .pill-soon { flex: none; }

/* My messages: one white card, one row per message. */
.msg-list { display: flex; flex-direction: column; margin: 0; padding: 4px 16px; list-style: none; background: var(--surface); border: 1px solid var(--line); border-radius: 18px; }
.msg-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 64px;
  padding: 14px 0;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
  font-family: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.msg-list > :last-child .msg-row,
.msg-list > .msg-row:last-child { border-bottom: 0; }
.msg-row > svg { flex: none; color: var(--navy); }
.msg-words { display: flex; flex: 1; flex-direction: column; gap: 4px; min-width: 0; }
.msg-from { font-size: var(--t22); font-weight: 700; line-height: 1.25; overflow-wrap: anywhere; }
.msg-line { font-size: var(--t19); line-height: 1.35; overflow-wrap: anywhere; }

/* Interim: the old Settings page ends with Sign out (js/main.js withSignOut). */

/* --- redesign: today (today.js, card.js) --- */
/* Today (frames 1a to 1d) and the shared verdict card with its "Still
   unsure?" row (frames 1l to 1n). Built on the shared components above
   (.screen, .hero-card, .allclear, .row-card, .btn-choice.is-compact,
   .btn-back, .btn-listen, .soon-button); only what they do not cover is here.

   Today
     .td-choices      "Check something yourself": the title and the three
                      choices, 12px apart
     .td-head         the card screen's row: back, .td-count ("2 of 3", 19px
                      bold grey) and Listen pushed to the right
     .td-dock         the answer bar with its one verb, full width
   The verdict card (js/views/card.js), on .v2-card for the slide to throw
     .vcard           white, 4px border in the verdict colour (.danger,
                      .caution, .ok), 26px corners, 20px padding, 14px gaps
     .vcard-word      the 60px .vcard-mark circle and the word, 36px
     .vcard-headline  26px; .vcard-next 22px bold; .vcard-fact 22px in the
                      verdict wash; .vcard-small 19px grey
     .vcard-fold      "Show me the message", the underlined text button;
                      .vcard-body the message, on the grey ground
     .vcard-unsure    "Still unsure?": the title, Ask, Send it to Prudence,
                      .vcard-note (19px grey); .vcard-doubt the folded button */

.td-choices { display: flex; flex-direction: column; gap: 12px; }
.td-count { flex: none; color: var(--muted); font-size: var(--t19); font-weight: 700; white-space: nowrap; }
.td-head .btn-listen { margin-left: auto; }
/* The card's answer bar holds one verb now (Throw it away, Call <name>, or
   on a Safe card Keep it): the full width, icon and word on one line. */
.v2-actions.td-dock { grid-template-columns: minmax(0, 1fr); }
.td-dock .v2-action { flex-direction: row; gap: 12px; min-height: 72px; font-size: var(--t22); }

.v2-card.vcard {
  gap: 14px;
  padding: 20px;
  border: 4px solid var(--line);
  border-radius: 26px;
  box-shadow: none;
}
.vcard p { margin: 0; }
.vcard.danger { border-color: var(--scam); }
.vcard.caution { border-color: var(--careful); }
.vcard.ok { border-color: var(--safe); }
.vcard-word {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  font-size: var(--t36);
  font-weight: 700;
  line-height: 1.05;
  overflow-wrap: anywhere;
}
.vcard.danger .vcard-word { color: var(--scam); }
.vcard.caution .vcard-word { color: var(--careful); }
.vcard.ok .vcard-word { color: var(--safe); }
.vcard-mark { flex: none; width: 60px; height: 60px; display: grid; place-items: center; border-radius: 50%; }
.vcard.danger .vcard-mark { background: var(--scam); color: var(--surface); }
.vcard.caution .vcard-mark { background: var(--careful-wash); border: 3px solid var(--careful); color: var(--careful); }
.vcard.ok .vcard-mark { background: var(--safe-wash); border: 3px solid var(--safe); color: var(--safe); }
.vcard-headline { margin: 0; font-size: var(--t26); font-weight: 700; line-height: 1.25; overflow-wrap: anywhere; }
.vcard-next { font-size: var(--t22); font-weight: 700; line-height: 1.4; }
.vcard-fact { padding: 12px 14px; border-radius: 14px; background: var(--ground); font-size: var(--t22); line-height: 1.4; overflow-wrap: anywhere; }
.vcard.danger .vcard-fact { background: var(--scam-wash); }
.vcard.caution .vcard-fact { background: var(--careful-wash); }
.vcard.ok .vcard-fact { background: var(--safe-wash); }
.vcard-small { color: var(--muted); font-size: var(--t19); line-height: 1.4; }
.vcard .vcard-fold { align-self: flex-start; min-height: 64px; margin-top: -4px; padding: 0; font-size: var(--t19); }
.vcard-body { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px; border-radius: 14px; background: var(--ground); }
.vcard-body audio { width: 100%; }
.vcard-body .mail-meta { font-size: var(--t19); }
.vcard-body .mail-body { margin: 0; font-size: var(--t19); }

.vcard-unsure,
.vcard-unsure-row { display: flex; flex-direction: column; gap: 12px; }
.vcard-unsure-row[hidden] { display: none; }
.vcard-unsure .btn-big { border-radius: 16px; }
.vcard-unsure .btn-big svg { flex: none; }
.vcard-note { margin: 0; color: var(--muted); font-size: var(--t19); line-height: 1.4; }
.vcard-doubt { justify-content: space-between; text-align: left; }
/* Look closer (card.js lookCloserHtml, _product/specs/investigate.md): the
   busy line, "Prudence checked:" with one numbered line per check (22px),
   then the closer verdict in its own wash and border (a smaller word and
   mark than the card's), each reason with its "Check n" chip, and the small
   source line. Words wrap at the Largest size; colour is never alone. */
.vcard-checks { display: flex; flex-direction: column; gap: 12px; }
.vcard-checks[hidden] { display: none; }
.vcard-checks p { margin: 0; }
.vcard-checks-busy { display: flex; align-items: center; gap: 10px; color: var(--navy); font-size: var(--t22); font-weight: 700; line-height: 1.35; }
.vcard-checks-busy svg { flex: none; }
.vcard-checks-note { font-size: var(--t22); line-height: 1.4; }
.vcard-check-list { display: flex; flex-direction: column; gap: 8px; margin: 0; padding-left: 1.6em; font-size: var(--t22); line-height: 1.4; overflow-wrap: anywhere; }
.vcard-closer { display: flex; flex-direction: column; gap: 12px; padding: 16px; border: 3px solid var(--line); border-radius: 20px; background: var(--surface); }
.vcard-closer .vcard-word { font-size: var(--t26); }
.vcard-closer .vcard-mark { width: 44px; height: 44px; }
.vcard-closer-do { font-size: var(--t22); line-height: 1.4; }

/* --- redesign: learn (learn.js) --- */
/* Frame 1o, the Learn home: the progress card (the 34px star beside "Your
   first star is one minute away" or the progress line, 22px bold navy), the
   badge row (one 48px circle per lesson: grey and faded until earned, then
   in colour on the navy wash) and the line under it (19px grey). Frame 1p:
   the lesson screens sit 8px under the header, 14px between blocks. */
.learn-progress-head { display: flex; align-items: center; gap: 12px; color: var(--navy); font-size: var(--t22); font-weight: 700; line-height: 1.25; overflow-wrap: anywhere; }
.learn-progress-head > svg { flex: none; }
.learn-badge-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0; list-style: none; }
.learn-badge-dot {
  flex: none;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--soon);
  font-size: 24px;
  line-height: 1;
  filter: grayscale(1);
  opacity: 0.7;
}
.learn-badge-dot.is-earned { background: var(--navy-wash); filter: none; opacity: 1; }
.learn-badge-line { color: var(--muted); font-size: var(--t19); line-height: 1.35; }
.learn-star-row.is-big { gap: 6px; }
.learn-minutes { white-space: nowrap; }
.learn-start > svg,
.learn-cue > svg { flex: none; }
/* Read by a screen reader, not shown (an earned badge's name). */
.learn-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.learn.learn-run { gap: 14px; margin-top: -12px; }

/* --- redesign: messages and blocked (mail.js) --- */
/* My messages (frame 1e) and Blocked (frame 1f), and the message they open
   in place (the shared card, frames 1l to 1n). Built on .screen, .chip-small,
   .msg-list, .msg-row, .row-card, .pill-verdict, .btn-outline and .btn-back;
   only what those do not cover is here.
     .pill-verdict.is-grey  "Not checked yet" and "Put back by you": grey
                            outline, the word and an icon, never a verdict colour
     .msg-wait              "Please wait a moment." while the list loads
     .blk-list              the Blocked cards, 12px apart
     .blk-words             a Blocked card's words, a button that opens the
                            message: the sender in quotes, subject · date, the pill
     .blk-none              "No scam this week", the green check first
     .msg-done              "Put back." or "Moved away." with its note, the
                            undo button under it (on a card and in a message)
     .msg-which             the sender and the subject above an open card
     .msg-moves             the move of an open message and its undo
     .msg-links             what "Check the links" found */
.pill-verdict.is-grey { background: var(--soon); border-color: var(--field); color: var(--muted); }
.msg-wait { margin: 0; font-size: var(--t22); color: var(--muted); }
.msg-screen .chip-row,
.blk-screen .screen-lead { margin: 0; }
.blk-title { margin-top: 12px; }
#blkList { display: flex; flex-direction: column; gap: 14px; }
.blk-list { display: flex; flex-direction: column; gap: 12px; margin: 0; padding: 0; list-style: none; }
.blk-put-title { margin-top: 8px; }
.blk-words {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  min-height: 64px;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 8px;
  color: var(--ink);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
.blk-none { display: flex; align-items: flex-start; gap: 10px; margin: 0; font-size: var(--t22); line-height: 1.4; }
.blk-none > svg { flex: none; margin-top: 0.15em; color: var(--safe); }
.msg-done { display: flex; flex-direction: column; gap: 4px; }
.msg-done p { margin: 0; }
.msg-done-line { display: flex; align-items: center; gap: 8px; color: var(--safe-ink); font-size: var(--t22); font-weight: 700; line-height: 1.3; }
.msg-done-line > svg { flex: none; color: var(--safe); }
.msg-done-note { font-size: var(--t19); line-height: 1.4; }
.msg-which { display: flex; flex-direction: column; gap: 4px; }
.msg-moves { display: flex; flex-direction: column; gap: 12px; }
.msg-moves > .btn,
.msg-open > .btn,
.blk-row > .btn { width: 100%; }
.msg-links { display: flex; flex-direction: column; gap: 8px; font-size: var(--t19); }
.msg-links .link-list { margin: 0; padding-left: 1.2em; }
.msg-open .trusted { margin: 0; }

/* --- redesign: check (check.js) --- */
/* Check something (frames 1g to 1n): the three choices, Paste the words,
   the screenshot and voice screens, the reading screen, the verdict. Built on
   the shared components (.screen, .btn-choice, .chip, .btn-back,
   .btn-listen, .banner, .row-card) and the verdict card (.vcard); only what
   they do not cover is here.

     .ck-screen       every Check screen (a .screen.is-snug)
     .ck-choices      frame 1g: 14px between the choices, as on the canvas;
                      .is-largest (frame 1h) tightens it so the three
                      choices stay above the tab bar
     .ck-text         the paste box: 150px, 2px grey border, 18px corners,
                      22px words
     .ck-question     a question and its chips, 10px apart
     .ck-problem      a sentence saying what went wrong, 22px (on .banner)
     .ck-preview      the 240px striped box the picture sits in while read
     .ck-wait         the ring (or the amber mark) and the line beside it
     .ck-wait-title   "Reading your picture…", 28px bold
     .ck-ring         the 56px ring, navy with one grey quarter; it turns,
                      slowly, only when the person allows motion
     .ck-mark         the 56px amber circle of "The check could not run"
     .ck-ask-panel    where "Ask <name>" draws its panel */

.ck-choices { gap: 14px; }
.ck-choices .screen-lead { margin-bottom: 6px; }
/* Largest (frame 1h): the three choices stay above the tab bar. */
.ck-choices.is-largest { gap: 8px; margin-top: -8px; }
.ck-choices.is-largest .screen-lead { margin-bottom: 0; }
.ck-choices.is-largest .btn-choice.is-hero { padding-top: 10px; padding-bottom: 10px; }
.ck-choices.is-largest .btn-choice:not(.is-hero) { min-height: 72px; }
.ck-photo .screen-lead { margin-bottom: 8px; }

.ck-text {
  display: block;
  width: 100%;
  min-height: 150px;
  margin: 0;
  padding: 16px;
  background: var(--surface);
  border: 2px solid var(--field);
  border-radius: 18px;
  color: var(--ink);
  font-family: inherit;
  font-size: var(--t22);
  line-height: 1.4;
  resize: none;
}
.ck-text::placeholder { color: var(--muted); opacity: 1; }
.ck-question { display: flex; flex-direction: column; gap: 10px; }
.ck-question .section-title { margin: 0; }
.ck-go { margin-top: 4px; }

.ck-problem { margin: 0; font-size: var(--t22); line-height: 1.4; }
.ck-problem[hidden] { display: none; }

.ck-preview {
  height: 240px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: repeating-linear-gradient(135deg, var(--surface) 0 12px, var(--ground) 12px 24px);
}
.ck-preview img { display: block; max-width: 100%; max-height: 240px; object-fit: contain; }
.ck-preview img[hidden] { display: none; }
.ck-wait { display: flex; align-items: center; gap: 14px; }
.ck-wait-title { margin: 0; font-size: var(--t28); font-weight: 700; line-height: 1.2; overflow-wrap: anywhere; }
.ck-ring {
  flex: none;
  box-sizing: border-box;
  width: 56px;
  height: 56px;
  border: 3px solid var(--navy);
  border-right-color: var(--line);
  border-radius: 50%;
}
@media (prefers-reduced-motion: no-preference) {
  .ck-ring { animation: ck-turn 3s linear infinite; }
}
@keyframes ck-turn { to { transform: rotate(360deg); } }
.ck-mark {
  flex: none;
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  border: 3px solid var(--careful);
  border-radius: 50%;
  background: var(--careful-wash);
  color: var(--careful);
}
.ck-stop { margin-top: 8px; }

.ck-more .row-card .row-name { margin: 0; }
.ck-more .row-card .row-state { display: block; }
.ck-ask-panel:empty { display: none; }

/* --- redesign: settings (settings.js) --- */
/* Settings and the screens under it (frames 1q, 1r, 1s). The rows are the
   shared .row-card, .row-head, .row-icon, .row-name, .row-state and the
   buttons above; what follows is only what those do not cover.
     .set-list        the setting cards, 10px apart (the canvas's list)
     .set-signout     Sign out, 6px below the last card
     .set-gap         a section title that opens a new part of a sub-screen
     .row-state.is-waiting  an invitation not answered yet: the clock in grey
     .set-reach       how a trusted person is reached, one line each (19px)
     .set-form, .set-field  the invitation and mobile number forms: 19px bold
                      labels over 64px fields with 22px words
     .set-remove, .set-confirm  Remove, and the question that replaces it
                      (Keep first, gold; then the red outline)
     .set-tech        the folded server address on the phone screen
     .set-pair        the pairing code and its QR, centred
     .set-items       What Prudence knows: one line per thing, the words then
                      Remove; the button drops under the words when both do
                      not fit (Largest)
     .set-events      What Prudence did: the date (19px grey) over the words
     .set-keep        Keep my account: 72px, 8px more above (frame 1s) */
/* What gets the keyboard focus is never left under the tab bar. */
.settings :focus { scroll-margin: 16px 0 calc(var(--tabbar-h, 80px) + 16px); }
.set-list { display: flex; flex-direction: column; gap: 10px; }
.set-signout { margin-top: 6px; }
.settings .section-title.set-gap { margin-top: 8px; }
.row-state.is-waiting > svg { color: var(--muted); }

.set-reach { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; font-size: var(--t19); line-height: 1.35; overflow-wrap: anywhere; }

.set-form { display: flex; flex-direction: column; gap: 12px; margin: 0; }
.set-field { display: flex; flex-direction: column; gap: 6px; margin: 0; font-size: var(--t19); font-weight: 700; line-height: 1.3; }
.set-field input { min-height: 64px; margin: 0; padding: 10px 14px; border-radius: 14px; font-size: var(--t22); }
.set-form > .btn { width: 100%; }

.set-remove { padding-top: 12px; border-top: 1px solid var(--line); }
.set-remove > .btn { width: 100%; }
.set-confirm { display: flex; flex-direction: column; gap: 10px; }
.set-confirm-q { margin: 0; font-size: var(--t22); font-weight: 700; line-height: 1.35; }

.set-tech { border-top: 1px solid var(--line); }
.set-tech summary { display: flex; align-items: center; min-height: 64px; color: var(--navy); font-size: var(--t19); font-weight: 700; text-decoration: underline; text-underline-offset: 4px; cursor: pointer; }
.set-tech[open] summary { margin-bottom: 4px; }
.set-pair { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; font-size: var(--t22); line-height: 1.35; }
.set-pair p { margin: 0; }
.set-pair .qr { line-height: 0; }
.set-pair-server { color: var(--muted); font-size: var(--t19); overflow-wrap: anywhere; }

.settings h2.row-name { margin: 0; }
.set-note { color: var(--muted); font-size: var(--t19); line-height: 1.35; }
.set-items { display: flex; flex-direction: column; margin: 0; padding: 0; list-style: none; }
.set-item { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 12px 0; border-top: 1px solid var(--line); }
.set-item:first-child { padding-top: 4px; border-top: 0; }
.set-item:last-child { padding-bottom: 0; }
.set-item-words { display: flex; flex: 1 1 9em; flex-direction: column; gap: 2px; min-width: 0; }
.set-item-name { font-size: var(--t22); font-weight: 700; line-height: 1.25; overflow-wrap: anywhere; }
.set-item-sub { font-size: var(--t19); line-height: 1.35; color: var(--muted); overflow-wrap: anywhere; }
.set-item > .btn { flex: 0 0 auto; }

.set-events { margin: 0; padding: 4px 16px; gap: 0; list-style: none; }
.set-event { display: flex; flex-direction: column; gap: 2px; padding: 12px 0; border-top: 1px solid var(--line); }
.set-event:first-child { border-top: 0; }
.set-event-when { color: var(--muted); font-size: var(--t19); line-height: 1.35; }
.set-event-what { font-size: var(--t22); line-height: 1.35; overflow-wrap: anywhere; }

.set-keep { min-height: 72px; margin-top: 8px; }

/* ---- 2026-11-04 protection score ---- */
/* The strip under Today's greeting (protection-menu.md, line 2b;
   renderScore() in js/protects.js): one compact row like a .row-card, the
   gauge then the words. Sizes in rem follow the person's text size, the
   gauge's too, so the count inside it grows with the words.
     .score         white, 1px #d8dee6 border, 18px corners, 12px 16px
                    padding: 80px tall at Normal with its 56px gauge, 6px
                    more and the Coming soon line's own lines under it
                    (the five short names of Nov 4 take two at 390 px)
     .score-gauge   the gauge, 56px at Normal: .score-track (the navy-wash
                    arc, deepened with a little navy: the plain wash does
                    not show on white), .score-bar (the gold share that is
                    on), .score-count ("3/5", navy bold; .is-long for a
                    longer count); decorative, the title says it in words
     .score-words   the title over the link, 2px apart
     .score-title   h2, 22px bold
     .score-step    the next step: 19px bold navy, underlined, a chevron
                    after (.score-step-end keeps it with the last word).
                    Its ::after covers the whole strip, so the tap area is
                    the strip (80px or more, the full width), not only the
                    words
     .score-soon    the grey "Coming soon: WhatsApp, ..." line under the
                    gauge and the words, the strip's full width (the strip
                    wraps: .score-words takes the rest of the first row and
                    never drops under the gauge), 19px muted, never a colour
                    of danger; inside the tap area like the rest */
.score {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
  padding: 12px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 18px;
}
.score:has(.score-step:hover) { background: var(--navy-wash); }
.score-gauge { flex: none; width: calc(56rem / 19); height: calc(56rem / 19); }
.score-track,
.score-bar { fill: none; stroke-width: 6; stroke-linecap: round; }
.score-track { stroke: color-mix(in srgb, var(--navy) 14%, var(--navy-wash)); }
.score-bar { stroke: var(--gold); }
/* In the gauge's own units (a 56 x 56 box): it scales with the gauge. */
.score-count { fill: var(--navy); font-family: var(--type); font-size: 16px; font-weight: 700; }
.score-count.is-long { font-size: 12px; }
.score-words { flex: 1 1 0; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 0; }
.score-title { margin: 0; font-size: var(--t22); font-weight: 700; line-height: 1.2; overflow-wrap: anywhere; }
.score-step {
  color: var(--navy);
  font-size: var(--t19);
  font-weight: 700;
  line-height: 1.3;
  text-decoration: underline;
  text-underline-offset: 4px;
  overflow-wrap: anywhere;
}
.score-step-end { white-space: nowrap; }
.score-step svg { margin-left: 2px; vertical-align: -0.2em; }
.score-step::after { content: ""; position: absolute; inset: 0; border-radius: 18px; }
.score-soon { flex: 1 0 100%; margin: 0; color: var(--muted); font-size: var(--t19); line-height: 1.3; overflow-wrap: anywhere; }

/* ---- 2026-11-04 Meta glasses (glasses.js, check-glasses.md) ---- */
/* The glasses screens, on the shared components (.screen, .btn-choice,
   .btn-gold, .btn-back, .banner, .row-card) and the Check styles (.ck-*).

     .gl-drawing      the drawing, the column's full width
     .gl-steps        numbered sentences: each number in a navy disc, drawn
                      here so the number is never a colour alone; .gl-marks
                      at 19px, so "They are on" stays above the tab bar
     .gl-question     a question and its answers
     .gl-said         the test sentence, written once it has been said
     .gl-ready-head   the green check beside "Your glasses are ready"
     .gl-free         "Without touching your phone"; .gl-then, .gl-say-words:
                      "Then say:" and the words to say
     .gl-say          "Say this out loud."
     .gl-sentence     the sentence in big white letters on navy
     .gl-level        the sound bar, navy on grey (.gl-level-bar; glasses.js
                      sets its transform, still for less motion)
     .gl-stopped      "Prudence stopped listening." */

.gl-drawing { display: block; width: 100%; height: auto; font-family: inherit; }
.gl-steps {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: gl-step;
  font-size: var(--t22);
  line-height: 1.35;
}
.gl-steps[hidden] { display: none; }
.gl-steps.gl-marks { gap: 8px; font-size: var(--t19); }
.gl-steps > li { position: relative; min-height: 36px; padding-left: 46px; counter-increment: gl-step; overflow-wrap: anywhere; }
.gl-steps > li::before {
  content: counter(gl-step);
  position: absolute;
  top: 0;
  left: 0;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--navy);
  color: var(--surface);
  font-size: 19px;
  font-weight: 700;
  line-height: 1;
}
.gl-question { display: flex; flex-direction: column; gap: 12px; }
.gl-question[hidden] { display: none; }
.gl-question .section-title { margin: 0; }
.gl-said { padding: 12px 14px; border-radius: 14px; background: var(--navy-wash); font-size: var(--t22); line-height: 1.4; overflow-wrap: anywhere; }
.gl-said[hidden] { display: none; }
.gl-screen .btn[hidden] { display: none; }
.gl-ready-head { display: flex; align-items: center; gap: 14px; }
.gl-ready-mark {
  flex: none;
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  border: 3px solid var(--safe);
  border-radius: 50%;
  background: var(--safe-wash);
  color: var(--safe);
}
.gl-free { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; padding-top: 16px; border-top: 1px solid var(--line); }
.gl-free .section-title { margin: 0; }
.gl-then { font-size: var(--t19); font-weight: 700; line-height: 1.3; }
.gl-say-words { padding: 12px 14px; border-radius: 14px; background: var(--navy-wash); font-size: var(--t22); font-weight: 700; line-height: 1.35; overflow-wrap: anywhere; }
.gl-say { font-size: var(--t22); font-weight: 700; line-height: 1.3; }
.gl-sentence {
  margin: 0;
  padding: 20px;
  border-radius: 22px;
  background: var(--navy);
  color: var(--surface);
  font-size: var(--t32);
  font-weight: 700;
  line-height: 1.2;
  /* Read aloud by her: a long word ("enregistrement" at French Largest) is
     hyphenated in the page's language, never cut anywhere. */
  overflow-wrap: break-word;
  hyphens: auto;
  -webkit-hyphens: auto;
}
.gl-level { height: 16px; overflow: hidden; border-radius: 8px; background: var(--line); }
.gl-level-bar {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--navy);
  transform: scaleX(0.03);
  transform-origin: left center;
}
@media (prefers-reduced-motion: no-preference) {
  .gl-level-bar { transition: transform 120ms linear; }
}
.gl-stopped { padding: 12px 14px; border-radius: 14px; background: var(--navy-wash); color: var(--navy); font-size: var(--t22); font-weight: 700; line-height: 1.35; }
