/*
 * CGP Invest design tokens.
 *
 * The only file that holds a raw value. Components reference the semantic
 * names below, never the scales directly, so a palette correction is one
 * edit here rather than a sweep through the interface.
 *
 * The brand colours are MEASURED, not estimated: sampled from the supplied
 * artwork by taking the median of each shape's eroded core, so anti-aliased
 * edges do not skew them. The marks in this directory are traced from that same
 * file rather than set in a substitute typeface.
 *
 * Unresolved: the low-resolution copies of the logo show a gold rule around the
 * badge. The high-resolution artwork has none, and a scan for warm pixels finds
 * zero, so the marks carry no metal. The brass scale below is therefore chosen
 * rather than sampled, and it is flagged until the firm confirms which artwork
 * is authoritative.
 */

:root {
  /* ---------------------------------------------------------- brand scales */

  /* Deep: the logo field. Carries the interface. Measured #034E69, which is
     hsl(196 94% 21%); the scale is that hue held constant. */
  --cgp-deep-900: #022A39;
  --cgp-deep-800: #023B4F;
  --cgp-deep-700: #034E69; /* logo, measured */
  --cgp-deep-600: #04678B;
  --cgp-deep-500: #0585B2;
  /* The two light steps carry text on the deep ground rather than being
     surfaces themselves: 300 is the quietest reading that still clears 4.5:1
     on deep-900, 200 the one that carries a row. */
  --cgp-deep-300: #7AA7B8;
  --cgp-deep-200: #AACDDA;
  --cgp-deep-100: #D1E4EB;
  --cgp-deep-050: #EBF4F7;


  /* Brass: a line and a letter colour, never a surface. This one is a
     decision, not a measurement: the artwork carries no metal, but the accent
     has to come from somewhere and every wealth-management identity worth
     looking at pairs a deep colour with one. Drop it and the accent becomes
     deep-600, which costs the engaging button its distinction. */
  --cgp-brass-700: #6F5A2C;
  --cgp-brass-600: #9A7B3E;
  --cgp-brass-500: #BFA268;
  --cgp-brass-200: #E3D7BC;
  --cgp-brass-100: #F3EDDE;

  /* Paper: warm neutrals, read off the palette of a real firm's premises.
     Never pure white, never blue-grey. */
  --cgp-paper-000: #FFFFFF;
  --cgp-paper-050: #FAF7F1;
  --cgp-paper-100: #F2EEE5;
  --cgp-paper-200: #E5DFD2;
  --cgp-paper-300: #D3CBBA;
  --cgp-paper-400: #A9A294;
  --cgp-ink-400: #9A9284;
  --cgp-ink-600: #6E675B;
  --cgp-ink-700: #4A443A;
  --cgp-ink-900: #1E1B16;

  /* State. Case state only. No colour on this platform ever encodes a
     medical reason, because no interface outside the officer's screen knows
     one. */
  --cgp-state-positive: #2E6B4F;
  --cgp-state-positive-bg: #E6EFE9;
  --cgp-state-waiting: #7A6128;
  --cgp-state-waiting-bg: #F3EDDE;
  --cgp-state-blocked: #8C3A32;
  --cgp-state-blocked-bg: #F5E7E4;
  /* The same alert, raised for the deep ground of the rail, where #8C3A32
     falls to 2:1 and stops being a warning at all. */
  --cgp-state-blocked-lifted: #D98C80;
  --cgp-state-sealed: #3B4B8C;
  --cgp-state-sealed-bg: #E8EAF5;

  /* Provenance. Where a case came from, which is not a state: the two strips
     over the case list divide it along different axes and may not share a
     colour. The firm's own cases carry the house deep blue; Troopay carries a
     violet of its own, chosen rather than measured, since they publish no
     palette. Both are text on their own ground and never a surface. */
  --cgp-origin-troopay: #743D85;
  --cgp-origin-troopay-bg: #F1E8F6;
  --cgp-origin-direct: var(--cgp-deep-700);
  --cgp-origin-direct-bg: var(--cgp-deep-050);

  /* ------------------------------------------------------- semantic colour */

  --color-surface: var(--cgp-paper-050);
  --color-surface-raised: var(--cgp-paper-000);
  --color-surface-sunken: var(--cgp-paper-100);
  --color-surface-inverse: var(--cgp-deep-700);

  --color-text: var(--cgp-ink-900);
  --color-text-muted: var(--cgp-ink-600);
  --color-text-inverse: var(--cgp-paper-000);
  --color-text-brand: var(--cgp-deep-700);
  --color-text-accent: var(--cgp-brass-700);

  --color-line: var(--cgp-paper-200);
  --color-line-strong: var(--cgp-paper-300);
  --color-line-brand: var(--cgp-deep-700);
  --color-line-accent: var(--cgp-brass-600);

  --color-focus: var(--cgp-deep-600);

  /* The rail is a plane of its own rather than a column of the page, so it
     carries the deep colour and its own ink, rules and focus ring. Nothing on
     the page's ground may be reused on this one: the page's focus colour
     disappears into it, and so does the alert red. */
  --color-surface-rail: var(--cgp-deep-900);
  --color-text-rail: var(--cgp-deep-200);
  --color-text-rail-muted: var(--cgp-deep-300);
  --color-text-rail-current: var(--cgp-paper-000);
  --color-line-rail: rgba(255, 255, 255, 0.14);
  --color-rail-hover: rgba(255, 255, 255, 0.06);
  --color-rail-current: rgba(255, 255, 255, 0.1);
  --color-focus-rail: var(--cgp-deep-200);

  /* Touch: a control a thumb hits is 56 px, not 40. Applies to the client
     journey at every width, and to the back office below 640 px. */
  --control-sm: 32px;
  --control-md: 40px;
  --control-lg: 48px;
  --control-touch: 56px;
  --hit-min: 44px;

  /* --------------------------------------------------------------- type */

  /* Display is a serif because the logo is a serif. UI is a sans because a
     case table is not an editorial page. Both carry the French diacritics.
     Neither is a default system pairing: the interface should not look like
     every other product a client has seen this week.

     Both are variable and self-hosted from `brand/fonts/`. Fraunces carries an
     optical size axis, so a heading at 56 px and a table name at 18 px are
     drawn differently rather than scaled; `font-optical-sizing` is left at its
     default, which is what applies it. */
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-ui: "Manrope", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-mono: ui-monospace, "SFMono-Regular", Menlo, monospace;

  /* Figures in a case table are compared down the column, not read as prose. */
  --numeric-tabular: tabular-nums;

  --text-display-xl: 3.5rem;   /* 56, desktop hero only */
  --text-display-lg: 2.75rem;  /* 44 */
  --text-display-md: 2rem;     /* 32, and the ceiling on a phone */
  --text-display-sm: 1.6875rem;/* 27 */
  --text-body-lg: 1.0625rem;   /* 17 */
  --text-body: 0.9375rem;      /* 15 */
  --text-body-sm: 0.8125rem;   /* 13 */
  --text-label: 0.6875rem;     /* 11, uppercase, tracked */

  --leading-tight: 1.15;
  --leading-snug: 1.35;
  --leading-body: 1.6;

  --tracking-display: -0.015em;
  --tracking-body: 0;
  --tracking-label: 0.11em;

  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;

  /* ------------------------------------------------------------- spacing */

  /* 4px base. Page rhythm is built from 8, 16, 24, 40, 64. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 40px;
  --space-8: 64px;
  --space-9: 96px;

  --measure-prose: 62ch;   /* legal and explanatory text */
  --measure-form: 34rem;   /* a question and its answers */
  --width-shell: 1360px;
  --width-rail: 238px;     /* becomes a drawer below 900px */
  --bp-mobile: 640px;
  --bp-tablet: 900px;

  /* ------------------------------------------------------- shape and depth */

  /* Four steps, and which one a thing takes says how big it is rather than how
     important. Controls are 12px: a button that size reads as something to
     press before it is read as a word. Surfaces take 16px, so a panel never
     looks tighter than the buttons inside it. The near-square frame of the logo
     survives as the frame motif and the marks themselves, not as the corner of
     every control. */
  --radius-xs: 6px;   /* a tick box, an avatar */
  --radius-sm: 8px;   /* small chips, the inner frame rule */
  --radius-md: 12px;  /* buttons, fields, choices, notices */
  --radius-lg: 16px;  /* panels, tables, dialogs */
  --radius-pill: 999px;

  --border-hairline: 1px;
  --border-frame: 1.5px;

  /* Elevation is a border first and a shadow second. Nothing floats without
     a reason; a dropdown has a reason, a card does not. */
  --shadow-none: none;
  --shadow-raised: 0 1px 2px rgba(15, 43, 53, 0.06);
  /* Under the pointer, and only there: a control says it can be pressed by
     answering the pointer, not by sitting raised on the page. */
  --shadow-lift: 0 8px 20px -8px rgba(2, 42, 57, 0.34), 0 2px 5px rgba(2, 42, 57, 0.10);
  --shadow-overlay: 0 12px 32px -8px rgba(15, 43, 53, 0.18),
                    0 2px 6px rgba(15, 43, 53, 0.08);

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

  /* Motion here confirms that an action landed. It never entertains, and it
     never delays an answer the person is waiting for. */
  --duration-press: 90ms;       /* the press itself, faster than the release */
  --duration-instant: 80ms;
  --duration-fast: 120ms;
  --duration-base: 180ms;
  --duration-exit: 160ms;       /* leaving is quicker than arriving, never instant */
  --duration-slow: 240ms;
  --duration-deliberate: 420ms; /* brand moments only: frame draw, seal */

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-exit: cubic-bezier(0.4, 0, 1, 1);
  /* One decelerating curve for something entering from off screen: the phone
     sheet. Still no overshoot anywhere, so nothing bounces. */
  --ease-soft: cubic-bezier(0.32, 0.72, 0, 1);

  /* How far a control rises under the pointer, and how far a view or an
     overlay travels as it arrives. Distances are values, so they live here. */
  --lift: 2px;
  --travel-step: 10px;
  --travel-overlay: 16px;

  --z-sticky: 100;
  --z-overlay: 400;
  --z-toast: 600;
}

/* A person who asks the system to calm down is obeyed everywhere, including
   in the brand moments. Opacity survives; movement does not. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-press: 1ms;
    --duration-instant: 1ms;
    --duration-fast: 1ms;
    --duration-base: 1ms;
    --duration-exit: 1ms;
    --duration-slow: 1ms;
    --duration-deliberate: 1ms;

    --lift: 0px;
    --travel-step: 0px;
    --travel-overlay: 0px;
  }
}


/* --------------------------------------------------------------- webfonts */

/* Self-hosted from `brand/fonts/`, never fetched from a third party: a font
   request carries the IP address of every person answering a health
   questionnaire, on the page that tells them their answers are protected.

   Two files sit on the critical path, latin only, 92 kB together. The extended
   latin range is a second request that only a name carrying one of its letters
   ever makes. Both faces are variable across the weights the interface uses, so
   a weight is a slice of one file rather than another download.

   `swap` rather than `block`: a page of Georgia that is readable at once beats
   a page of nothing, on a form where abandonment is the metric that matters. */

@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/assets/fonts/fraunces-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308,
                 U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/assets/fonts/fraunces-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
                 U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
                 U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/assets/fonts/manrope-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308,
                 U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/assets/fonts/manrope-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
                 U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
                 U+2C60-2C7F, U+A720-A7FF;
}

/* ------------------------------------------------------------------ reset */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--color-surface);
  color: var(--color-text);
  font-family: var(--font-ui);
  font-size: var(--text-body);
  line-height: var(--leading-body);
}
h1, h2, h3, p, figure, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img, svg { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
a { color: var(--color-text-accent); text-decoration: none; }
a:hover { color: var(--cgp-brass-600); text-decoration: underline; }
:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
/* A heading the script moves the focus to, so a screen reader starts reading at
   the top of what just appeared. Nobody tabbed to it, and a ring around a line
   of prose reads as a field to fill in. */
[tabindex="-1"]:focus { outline: none; }
[hidden] { display: none !important; }

/* ------------------------------------------------------------- typography */

.display-xl { font: 400 var(--text-display-xl) / 1.06 var(--font-display); letter-spacing: -0.03em; margin: 0; }
.display-lg { font: 400 var(--text-display-lg) / 1.08 var(--font-display); letter-spacing: -0.025em; margin: 0; }
.display-md { font: 400 var(--text-display-md) / 1.12 var(--font-display); letter-spacing: -0.02em; margin: 0; }
.display-sm { font: 400 var(--text-display-sm) / 1.2 var(--font-display); letter-spacing: -0.015em; margin: 0; }
.prose { font: 400 var(--text-body-lg) / 1.62 var(--font-display); color: var(--cgp-ink-700); max-width: var(--measure-prose); }
.muted { color: var(--color-text-muted); }
.small { font-size: var(--text-body-sm); }
.num { font-variant-numeric: var(--numeric-tabular); }
.mono { font-family: var(--font-mono); font-size: var(--text-body-sm); }

/* Tracked capitals: the counterweight to a display serif set large. */
.caps {
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.caps-accent { color: var(--color-text-accent); }

/* ---------------------------------------------------------------- layout */

.page { min-height: 100vh; display: flex; flex-direction: column; }
.wrap { width: 100%; max-width: 880px; margin: 0 auto; padding: 0 var(--space-5); }
.wrap-wide { width: 100%; max-width: var(--width-shell); margin: 0 auto; padding: 0 var(--space-6); }
.stack { display: flex; flex-direction: column; }
.row { display: flex; align-items: center; gap: var(--space-3); }
.grow { flex-grow: 1; }
.gap-2 { gap: var(--space-2); } .gap-3 { gap: var(--space-3); } .gap-4 { gap: var(--space-4); }
.gap-5 { gap: var(--space-5); } .gap-6 { gap: var(--space-6); } .gap-7 { gap: var(--space-7); }

/* A mark keeps its own size. A flex child is allowed to be squeezed below the
   width of its content, and what that looks like on a phone is a 19px icon
   drawn four pixels wide beside a paragraph that wrapped. Both spellings are
   here because a mark is sometimes the row's own child and sometimes wrapped in
   a span that carries its colour. */
.row > svg { flex: none; }
.mark { display: flex; flex: none; }

/* ---------------------------------------------------------------- brand */

.wordmark { display: flex; align-items: center; gap: var(--space-3); }
.wordmark img { width: 28px; height: 28px; }
.wordmark-name {
  font-family: var(--font-display); font-size: 0.8125rem; font-weight: var(--weight-medium);
  letter-spacing: 0.17em; text-transform: uppercase; color: var(--color-text-brand);
}

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

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: var(--control-md); padding: 0 var(--space-4);
  border: var(--border-hairline) solid transparent; border-radius: var(--radius-md);
  font-size: var(--text-body-sm); font-weight: var(--weight-medium); line-height: 1;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: background-color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-slow) var(--ease-out),
              transform var(--duration-slow) var(--ease-out);
}
.btn:hover { text-decoration: none; }

/* The one gesture every control makes: it rises to meet the pointer and takes
   the press. Nothing else moves on hover anywhere in the interface, so this
   reads as "you can press this" rather than as decoration. */
.btn:hover:not([disabled]):not([aria-disabled="true"]) {
  transform: translateY(calc(var(--lift) * -1));
  box-shadow: var(--shadow-lift);
}
.btn:active:not([disabled]):not([aria-disabled="true"]) {
  transform: translateY(0) scale(0.985);
  box-shadow: var(--shadow-raised);
  transition-duration: var(--duration-press);
}
/* A ghost button has no edge to cast one. */
.btn-ghost:hover:not([disabled]):not([aria-disabled="true"]) { box-shadow: none; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.42; cursor: not-allowed; }
.btn-lg { height: var(--control-lg); font-size: var(--text-body); padding: 0 var(--space-5); }
.btn-touch { height: var(--control-touch); font-size: 1rem; padding: 0 var(--space-5); }
.btn-sm { height: var(--control-sm); font-size: var(--text-body-sm); padding: 0 var(--space-3); }
.btn-block { width: 100%; }
/* A mark on its own. Square, so it reads as a control and not as a stray icon,
   and never without a title and a name for a reader that cannot see it. */
.btn-icon { width: var(--control-md); padding: 0; }

.btn-primary { background: var(--cgp-deep-700); color: var(--color-text-inverse); border-color: var(--cgp-deep-800);
                box-shadow: var(--shadow-raised); }
.btn-primary:hover:not([disabled]) { background: var(--cgp-deep-800); color: var(--color-text-inverse); }
.btn-secondary { background: transparent; color: var(--color-text-brand); border-color: var(--cgp-paper-300); }
.btn-secondary:hover:not([disabled]) { background: var(--cgp-paper-100); border-color: var(--color-line-accent); }
.btn-ghost { background: transparent; color: var(--color-text-brand); }
.btn-ghost:hover:not([disabled]) { background: var(--cgp-paper-100); }

/* The engaging button: the act that cannot be undone. One per screen, never two.
   Brass borders and writes, it never fills. */
.btn-commit { background: var(--color-surface-raised); color: var(--color-text-accent); border-color: var(--color-line-accent); }
.btn-commit:hover:not([disabled]) { background: var(--cgp-brass-100); color: var(--cgp-brass-700); }

/* No red fill: a red button invites the click it claims to discourage. */
.btn-danger { background: var(--color-surface-raised); color: var(--cgp-state-blocked); border-color: var(--cgp-paper-300); }
.btn-danger:hover:not([disabled]) { background: var(--cgp-state-blocked-bg); border-color: var(--cgp-state-blocked); }

/* ---------------------------------------------------------------- fields */

.field-label { display: block; margin-bottom: var(--space-2); }
.field {
  width: 100%; height: 44px; padding: 0 var(--space-3);
  background: var(--color-surface-raised); color: var(--color-text);
  border: var(--border-hairline) solid var(--cgp-paper-300); border-radius: var(--radius-md);
  transition: border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-base) var(--ease-out);
}
.field::placeholder { color: var(--cgp-paper-400); }
.field:hover { border-color: var(--color-line-accent); }
.field:focus { outline: 2px solid var(--color-focus); outline-offset: 1px; border-color: var(--color-focus);
               box-shadow: 0 0 0 3px var(--cgp-deep-050); }
.field[aria-invalid="true"] { border-color: var(--cgp-state-blocked); }
.field-code { font-variant-numeric: var(--numeric-tabular); letter-spacing: 0.24em; }
/* A field holding prose rather than a value. One screen has them: the wording
   of the message sent to a client. It grows downwards and never sideways, so a
   long paragraph does not push the form off a narrow window. */
.field-multiline { height: auto; min-height: 7rem; padding: var(--space-3);
                   line-height: var(--leading-body); resize: vertical; }

/* The wording of the client message beside what it produces. Two columns where
   there is room for both, the form first, and one below: reading the preview
   under the form is the same act one screen later, where reading it in a column
   narrower than a mail is reading a different message.

   The right column is not a share of the width, it is a measurement: a mail is
   560px of card inside 16px of page on each side. The card gives way below that
   rather than overflow, so a narrower column would not cut the message off, it
   would show it reflowed to a width most recipients do not read it at.
   Everything left over is the form's, which needs no particular width. */
.message-edit { display: grid; grid-template-columns: minmax(0, 1fr) 42rem;
                gap: var(--space-5); align-items: start; }
/* Measured against the window and not the column: the rail takes its width
   out of the two before either of them is laid out. Below this the form would
   be the one squeezed, so the two stack instead. */
@media (max-width: 1400px) { .message-edit { grid-template-columns: minmax(0, 1fr); } }
/* The subject, over the message rather than inside it: no rendering carries it,
   and it is the line the recipient reads first. Set like the header of a mail
   client, a label and a value on one rule. */
.mail-subject { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-3);
                padding-bottom: var(--space-3); border-bottom: 1px solid var(--color-line); }
.mail-subject .caps { color: var(--color-text-muted); }

/* The message itself, drawn in its own document. The frame is the width of the
   column, and the card inside it is 560px or the width of the frame, whichever
   is smaller, which is what it does in a mail client.
   The height is set by the script from the content; this one is what it starts
   at and what it keeps when no script runs, tall enough for the message without
   an empty screen under it. */
.mail-frame { display: block; width: 100%; height: 54rem; border: var(--border-hairline) solid var(--color-line);
              border-radius: var(--radius-md); background: var(--color-surface-sunken); }

/* The message as it leaves: its own line breaks, wrapped, never a scrollbar
   sideways. It is text and not code, so it keeps the reading typeface. */
.message-preview { margin: var(--space-3) 0 0; white-space: pre-wrap; overflow-wrap: anywhere;
                   font-family: inherit; color: var(--color-text-muted);
                   line-height: var(--leading-body); }
.field-error { display: block; margin-top: var(--space-2); font-size: var(--text-body-sm); color: var(--cgp-state-blocked); }
.field-help { display: block; margin-top: var(--space-2); font-size: var(--text-body-sm); color: var(--color-text-muted); }

/* ------------------------------------------------------- closed answers */

.choice {
  display: flex; align-items: center; gap: var(--space-3);
  min-height: var(--control-touch); padding: 0 var(--space-4);
  background: var(--color-surface-raised);
  border: var(--border-hairline) solid var(--cgp-paper-300); border-radius: var(--radius-md);
  cursor: pointer; font-size: var(--text-body-lg);
  transition: border-color var(--duration-fast) var(--ease-out),
              background-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-base) var(--ease-out),
              transform var(--duration-base) var(--ease-out);
}
.choice:hover { border-color: var(--color-line-accent); transform: translateY(calc(var(--lift) * -0.5)); }
.choice input { position: absolute; opacity: 0; width: 0; height: 0; }
.choice-dot {
  width: 19px; height: 19px; flex-shrink: 0; border-radius: var(--radius-pill);
  border: 1px solid var(--cgp-paper-400);
  transition: border var(--duration-instant) var(--ease-out);
}
.choice:has(input:checked) { border-color: var(--cgp-deep-700); background: var(--cgp-deep-050); box-shadow: inset 0 0 0 1px var(--cgp-deep-700); }
.choice:has(input:checked) .choice-dot { border: 5.5px solid var(--cgp-deep-700); }
.choice:has(input:focus-visible) { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* A tick is a declaration, not a preference: square, and it says what it commits to. */
.check {
  display: flex; align-items: center; gap: var(--space-3);
  cursor: pointer; line-height: 1.5;
}
.check input { position: absolute; opacity: 0; width: 0; height: 0; }
.check-box {
  width: 19px; height: 19px; flex-shrink: 0; border-radius: var(--radius-xs);
  border: 1px solid var(--cgp-paper-400); background: var(--color-surface-raised);
  transition: border-color var(--duration-fast) var(--ease-out), background-color var(--duration-fast) var(--ease-out);
}
.check:hover .check-box { border-color: var(--color-line-accent); }
.check:has(input:checked) .check-box {
  background: var(--cgp-deep-700); border-color: var(--cgp-deep-700);
  box-shadow: inset 0 0 0 2px var(--color-surface-raised), inset 0 0 0 9px var(--cgp-deep-700);
}
.check:has(input:focus-visible) .check-box { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* ------------------------------------------------------ open answers */

/* Free text is where the detail of an answer is, so it is given room rather
   than a single line the client has to fight. */
.field-area { height: auto; min-height: 88px; padding: var(--space-3); resize: vertical; line-height: 1.5; }
.measure { display: flex; align-items: center; gap: var(--space-3); }
.measure .field { max-width: 140px; }
.measure-unit { font-size: var(--text-body-sm); color: var(--color-text-muted); }

/* What a yes opens up. Set in, so it reads as belonging to the question above. */
.aside {
  padding-left: var(--space-4);
  border-left: 2px solid var(--color-line-accent);
  max-width: 560px;
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* --------------------------------------------------------- surfaces */

.panel {
  background: var(--color-surface-raised);
  border: var(--border-hairline) solid var(--color-line);
  border-radius: var(--radius-lg);
  padding: var(--space-5) var(--space-5);
}

/* The frame: the logo rules its wordmark, and the interface repeats the gesture.
   Once per screen, on the thing that matters. */
.frame {
  background: var(--color-surface-raised);
  border: var(--border-hairline) solid var(--color-line);
  border-radius: var(--radius-lg);
  padding: 6px;
}
.frame-inner {
  border: var(--border-hairline) solid var(--cgp-brass-200);
  border-radius: var(--radius-md);
  padding: var(--space-5) var(--space-5);
}

.notice { display: flex; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); }
.notice svg { flex-shrink: 0; margin-top: 2px; }
.notice-info { background: var(--cgp-deep-050); color: var(--cgp-deep-700); }
.notice-warn { background: var(--cgp-state-waiting-bg); border: var(--border-hairline) solid var(--cgp-brass-200); color: var(--cgp-ink-700); }
.notice-error { background: var(--cgp-state-blocked-bg); border: var(--border-hairline) solid var(--cgp-state-blocked); color: var(--cgp-ink-700); }

/* ----------------------------------------------------------------- state */

/* Case state, never a medical reason: no interface outside the expert's
   screen knows one, so no colour here can encode one. */
.state { display: inline-flex; align-items: center; padding-left: var(--space-3); border-left: 2px solid var(--cgp-paper-300); }
.state-positive { border-left-color: var(--cgp-state-positive); }
.state-waiting  { border-left-color: var(--cgp-brass-600); }
.state-sealed   { border-left-color: var(--cgp-state-sealed); }
.state-blocked  { border-left-color: var(--cgp-state-blocked); }
.state-neutral  { border-left-color: var(--cgp-ink-600); }

/* The division of the case list, offered on the screen rather than in the rail:
   these are queries over one place, and the rail names places. */
/* The two divisions of the case list, side by side: the shapes of work on the
   left, where the eye starts, and the provenance on the right. They wrap onto
   two lines below the width that fits both, and the caption is what keeps the
   second group from reading as more shapes of work. */
.views-bar { display: flex; flex-wrap: wrap; align-items: center;
             justify-content: space-between; gap: var(--space-3) var(--space-5);
             margin-top: var(--space-5); }
.views-bar .views { margin-top: 0; }
.views-origin { align-items: center; }
.views-caption { color: var(--color-text-muted); margin-right: var(--space-1); }
.views { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-5); }
/* Every chip carries the colour of what it selects, and wears it only once it
   is the one on screen: a strip where nothing is chosen is a strip of quiet
   outlines, and the choice is the one thing in colour. Two variables carry it,
   so the rules below are written once and each chip sets its own pair.

   Selected is the tinted ground of that colour rather than a solid fill of the
   house blue. The solid fill made every chosen chip the same object whatever it
   selected, and it was the darkest thing on a page of paper. The ring is drawn
   inside the border rather than by thickening it, because a border that grows
   on selection moves the chips beside it. */
.view { --view-tint: var(--cgp-ink-700); --view-ground: var(--cgp-paper-100);
        display: inline-flex; align-items: baseline; gap: var(--space-2);
        padding: var(--space-2) var(--space-4); border-radius: var(--radius-pill);
        border: var(--border-hairline) solid var(--color-line);
        font-size: var(--text-body-sm); color: var(--color-text-muted);
        transition: color var(--duration-fast) var(--ease-out),
                    border-color var(--duration-fast) var(--ease-out),
                    background-color var(--duration-fast) var(--ease-out); }
.view:hover { text-decoration: none; color: var(--view-tint); border-color: var(--view-tint); }
.view[aria-current="page"] { background: var(--view-ground); border-color: var(--view-tint);
                             color: var(--view-tint); box-shadow: inset 0 0 0 1px var(--view-tint); }
.view-count { font-variant-numeric: var(--numeric-tabular); }

/* One colour per view, and each is the colour that state already has in the
   table: the cases in progress take the sealed blue of the ones among them
   waiting to be read, an acceptance is green. A refusal takes the ink
   rather than the red: it is a file that closed, not something to act on, and
   the red on this strip belongs to the transmissions that have stalled. */
.view-in-progress { --view-tint: var(--cgp-state-sealed); --view-ground: var(--cgp-state-sealed-bg); }
/* The call still to make is the accent rather than a state colour: it is the
   only view that asks somebody to do something outside this service, and brass
   is what this design gives to an act. It sits next to the green of the files
   that are done, which is the pile it was taken out of. */
.view-to-contact { --view-tint: var(--cgp-brass-700); --view-ground: var(--cgp-brass-100); }
.view-accepted  { --view-tint: var(--cgp-state-positive); --view-ground: var(--cgp-state-positive-bg); }
.view-refused   { --view-tint: var(--cgp-ink-700);        --view-ground: var(--cgp-paper-100); }
.view-failed    { --view-tint: var(--cgp-state-blocked);  --view-ground: var(--cgp-state-blocked-bg); }
/* The failure view is offered only when it holds something, so it may carry the
   alert colour outright rather than wait to be chosen. */
.view-failed:not([aria-current]) { color: var(--view-tint); border-color: var(--view-tint); }

/* The provenance, whose colours are the two houses rather than three more
   states: Troopay's violet, the firm's own deep blue, and no colour at all for
   the chip that narrows nothing. */
.view-origin-all     { --view-tint: var(--cgp-ink-700); --view-ground: var(--cgp-paper-100); }
.view-origin-troopay { --view-tint: var(--cgp-origin-troopay); --view-ground: var(--cgp-origin-troopay-bg); }
.view-origin-direct  { --view-tint: var(--cgp-origin-direct);  --view-ground: var(--cgp-origin-direct-bg); }
/* One pane per view, all rendered, one shown, and every pane holds the cases of
   both provenances. Switching either strip is a change of what is on screen and
   not a page, so neither one makes a round trip. */
.view-pane { margin-top: var(--space-5); }

/* ---------------------------------------------------------------- tables */

.table { width: 100%; background: var(--color-surface-raised);
         border: var(--border-hairline) solid var(--color-line); border-radius: var(--radius-lg);
         border-collapse: separate; border-spacing: 0; overflow: hidden; }
.table th { text-align: left; padding: var(--space-3) var(--space-5); border-bottom: 1px solid var(--color-line); }
/* An address is one word to a browser, and a table sized to the longest word in
   it pushes the whole page sideways on anything narrower than a desktop. It is
   `anywhere` rather than `break-word` because only the former lets the column
   be measured at the narrower width; the latter breaks the line but leaves the
   table claiming room it never needed. */
.table td { padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--color-surface);
            vertical-align: baseline; overflow-wrap: anywhere; }
.table tbody tr:last-child td { border-bottom: none; }
/* A table narrowed in the browser has a last row that is not its last child,
   and the rule above would leave a rule hanging under it. The script names it. */
.table tbody tr.row-last td { border-bottom: none; }
.table tbody tr { transition: background-color var(--duration-fast) var(--ease-out); }
.table tbody tr:hover { background: var(--color-surface); }
/* A row that leads somewhere is the target itself: the pointer says so, and the
   link inside it stays the keyboard's way in. */
.table tbody tr[data-open] { cursor: pointer; }
/* The applicant is a person, not a cell. */
.table .who { font: 400 1.125rem/1.2 var(--font-display); }
.table a.who:hover { text-decoration: none; color: var(--color-text-brand); }

.empty { padding: var(--space-8) var(--space-5); text-align: center; color: var(--color-text-muted); }

/* --------------------------------------------------------------- dossier */

/* The case screen: a band of context, the questionnaire, and the act that closes
   it. Three full width blocks and no column of its own for anything.

   The arrangement it replaced put the file on the left and what had happened to
   it on the right. That column only ever filled at the foot of the page, below a
   dossier read across the full width, so an expert reached the end of a
   questionnaire and found the verdict form squeezed into a third of the screen
   with a timeline stranded beside it. See knowledge/decisions/0037. */

.case-band { padding: 0; overflow: hidden; margin-bottom: var(--space-6); }
.case-band-head {
  display: flex;
  align-items: flex-end;
  gap: var(--space-5);
  flex-wrap: wrap;
  padding: var(--space-5) var(--space-5) var(--space-4);
}
/* A measure rather than a fraction: the name and its dates set their own width,
   and the documents take what is left rather than half of everything. */
.case-band-said { flex: 1 1 24rem; min-width: 0; }
.case-band-files { flex: 0 1 auto; align-items: flex-end; text-align: right; }

/* The life of the file, standing up, in the dialogue that holds it.

   It used to lie across the foot of the band on every case screen, six steps in
   a row, and it is now one button away: knowledge/decisions/0058. A dialogue is
   narrow, so the rail is the only layout left. The dots take a column of their
   own and the rule runs down it from one step to the next, so the steps read as
   one thread rather than as a list of dates.

   Each step is three short registers, what it is, what it says and when. */
.case-track { display: flex; flex-direction: column; margin: 0; padding: 0; list-style: none; }
.case-step {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto auto auto;
  column-gap: var(--space-3);
  row-gap: var(--space-1);
  align-items: start;
  min-width: 0;
}
.case-step-rule {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  grid-row: 1 / -1;
  align-self: stretch;
  /* The dot sits on the label's first line rather than on the top of its box. */
  padding-top: 3px;
}
.case-step-rule > span { flex: 1 1 auto; width: 1px; background: var(--color-line-strong); }
.case-step-done .case-step-rule > span { background: var(--cgp-deep-700); }
/* The last step closes the track, so it draws no rule into the margin. */
.case-step:last-child .case-step-rule > span { display: none; }
/* The gap between two steps belongs to the step above, so the rule spans it
   rather than stopping at the text and starting again below it. */
.case-step > span:last-child { padding-bottom: var(--space-3); }
.case-step:last-child > span:last-child { padding-bottom: 0; }
.case-step-value { font-weight: var(--weight-medium); }
.case-step-pending .case-step-label,
.case-step-pending .case-step-value { color: var(--color-text-muted); }

/* The conclusion, worn beside the name rather than restated in a panel. Tinted
   ground and no border: it is a fact about the file, not a control, and the one
   bordered thing on this screen is the block carrying what is left to do. */
.case-verdict {
  align-self: center;
  border-radius: var(--radius-pill);
  padding: var(--space-1) var(--space-3);
  white-space: nowrap;
}
/* Green and ink rather than green and red. A refusal is a file that closed, not
   an alert, which is the reading the case list already takes. */
.case-verdict-yes { color: var(--cgp-state-positive); background: var(--cgp-state-positive-bg); }
.case-verdict-no { color: var(--cgp-ink-700); background: var(--cgp-paper-100); }
/* A transmission that is not leaving, beside the conclusion it is about. Red
   where the two verdicts are not, because this one is the only thing on the
   band somebody has to act on. The cursor says the mark explains itself on
   hover, since its tooltip is where the count and the usual cause now live. */
.case-verdict-blocked {
  color: var(--cgp-state-blocked);
  background: var(--cgp-state-blocked-bg);
  cursor: help;
}
/* The name and its mark share a baseline and wrap together rather than the mark
   dropping under a name that broke. */
.case-band-name { align-items: baseline; flex-wrap: wrap; row-gap: var(--space-2); }

/* The address and the number, as two values to take away rather than two links.
   What somebody does with them is paste them into the tool they write the quote
   in, and a mailto: opens whatever the workstation declares, which is often
   nothing. Each field is capped: an address is long and a number is short, and a
   field that took the whole band would read as an input somebody should fill. */
.contact-fields { flex-wrap: wrap; row-gap: var(--space-3); margin-top: var(--space-2); }
.copy-field { flex: 1 1 15rem; max-width: 22rem; min-width: 0; }
.copy-row { display: flex; gap: var(--space-2); align-items: center; }
.copy-row .field { flex: 1 1 auto; min-width: 0; height: var(--control-md); }
/* Read only and not disabled: a disabled input takes no focus, so its text
   cannot be selected and the value becomes a picture of itself. It reads as a
   value rather than as something to fill, which is what the tinted ground says. */
.copy-row .field[readonly] { background: var(--color-surface); cursor: text; }
.copy-row .field[data-empty] { color: var(--color-text-muted); font-style: italic; }
.copy-row .btn { flex: 0 0 auto; }
/* The button says it worked where it happened, for as long as it takes to read.
   A notice at the top of the screen for a value put on a clipboard would be a
   larger event than the act. The mark becomes a check rather than growing a
   word beside it: a button that widens on a press pushes the field next to it. */
.copy-mark, .copy-done { display: flex; }
.copy-done, .btn[data-copied] .copy-mark { display: none; }
.btn[data-copied] .copy-done { display: flex; }

/* What the file still owes: one block, one frame, one engaging button. Two
   panels stood here, each with its own frame and three sentences of its own,
   and a file that owed both had them competing. */
.case-next {
  border-color: var(--color-line-accent);
  border-width: var(--border-frame);
  margin-bottom: var(--space-6);
}
.case-next-row {
  display: flex;
  align-items: center;
  gap: var(--space-5) var(--space-7);
  flex-wrap: wrap;
  padding-top: var(--space-4);
}
/* The rule separates two things owed; it is not drawn above the first. */
.case-next-row + .case-next-row {
  margin-top: var(--space-4);
  border-top: var(--border-hairline) solid var(--color-line);
}
.case-next-say { flex: 1 1 22rem; min-width: 0; }
.case-next-act { flex-wrap: wrap; }
.case-next-act .btn { height: var(--control-lg); }

/* The conclusion, at the width of the reading it follows. The brass frame is the
   frame motif spent once per screen, on the thing that matters. */
.case-close { border-color: var(--color-line-accent); border-width: var(--border-frame); }
.case-close-row { display: flex; align-items: flex-end; gap: var(--space-7); flex-wrap: wrap; }
.case-close-say { flex: 1 1 24rem; min-width: 0; }
.case-close-act { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
/* The commit takes a choice's height rather than a button's, so the three sit on
   one line rather than one of them riding 8px short. */
.case-close-act .btn { height: var(--control-touch); }
/* The refusal takes the whole row under the controls rather than joining them. */
.case-close-act .notice { flex: 1 0 100%; }

/* The band's two halves separate before the page does, because a name at 44px
   and a row of buttons stop sharing a line well before the screen is narrow. */
@media (max-width: 1100px) {
  .case-band-files { flex-basis: 100%; align-items: flex-start; text-align: left; }
}

/* --------------------------------------------------------------- shells */

.topbar { display: flex; align-items: center; gap: var(--space-4);
          height: 60px; padding: 0 var(--space-5);
          background: var(--cgp-paper-100); border-bottom: 1px solid var(--cgp-paper-300); }
/* The back office's bar exists for the drawer handle, so it exists where the
   drawer does and nowhere else. Above 900px the rail runs the full height and
   carries the mark itself. */
.topbar-staff { display: none; }
.shell { flex-grow: 1; display: flex; min-height: 0; }
/* The rail is a plane, not a column of the same sheet. It takes the deep colour
   and drops its right-hand rule: a plane does not need a line to say where it
   ends. Everything inside it reads off the rail tokens, because the page's ink,
   its focus ring and its alert red all disappear on this ground. */
/* The rail is held to the window and not to the length of the page. Stretched
   by the shell it was as tall as the content, so the way out sat at the foot of
   a long dossier rather than at the foot of the screen, and a reader had to
   scroll a case to reach it. Stretching is what align-self turns off; the
   overflow is for the day a rail outgrows a short window. */
.rail { width: var(--width-rail); flex-shrink: 0; background: var(--color-surface-rail);
        position: sticky; top: 0; align-self: flex-start; height: 100vh; overflow-y: auto;
        padding: var(--space-5) var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); }
.rail-head { padding: 0 var(--space-3) var(--space-5); }
.rail .wordmark-name { color: var(--color-text-rail-current); }
.rail .caps { color: var(--color-text-rail-muted); }
.rail :focus-visible { outline-color: var(--color-focus-rail); }
.rail-section { padding: 0 var(--space-3); margin-top: var(--space-4); }
.rail-section:first-of-type { margin-top: 0; }
.rail a { display: flex; align-items: center; gap: var(--space-3); min-height: var(--hit-min);
          padding: var(--space-3); border-radius: var(--radius-md); color: var(--color-text-rail);
          border: var(--border-hairline) solid transparent;
          transition: background-color var(--duration-fast) var(--ease-out); }
.rail a:hover { background: var(--color-rail-hover); color: var(--color-text-rail-current); text-decoration: none; }
.rail a[aria-current="page"] { background: var(--color-rail-current); color: var(--color-text-rail-current);
  font-weight: var(--weight-medium); box-shadow: inset 2px 0 0 var(--cgp-brass-500); }
.rail .count { margin-left: auto; font-size: var(--text-label); font-weight: var(--weight-medium);
               color: var(--cgp-brass-500); font-variant-numeric: var(--numeric-tabular); }
.rail .count-alert { color: var(--cgp-state-blocked-lifted); }
/* Without the rule, the content stands off the plane on its own margin. */
.main { flex-grow: 1; min-width: 0; padding: var(--space-6) var(--space-7) var(--space-8); }
.page-head { display: flex; align-items: flex-end; gap: var(--space-5); flex-wrap: wrap; margin-bottom: var(--space-5); }

/* The way out, closing the rail. It sits under a rule below the last section and
   wears a rail row's hover, because it is reached the same way as the rest of the
   rail without being one of the places the rail leads to. */
.rail-foot { margin-top: auto; padding-top: var(--space-3); border-top: 1px solid var(--color-line-rail);
             display: flex; flex-direction: column; gap: var(--space-2); }

.rail-out button { width: 100%; display: flex; align-items: center; gap: var(--space-3);
                   min-height: var(--hit-min); padding: var(--space-3);
                   border: var(--border-hairline) solid transparent; border-radius: var(--radius-md);
                   background: none; color: var(--color-text-rail); font: inherit; text-align: left;
                   cursor: pointer; transition: background-color var(--duration-fast) var(--ease-out); }
.rail-out button:hover { background: var(--color-rail-hover); color: var(--color-text-rail-current); }

/* The drawer: a checkbox, its handle and the veil behind it. All three are inert
   above 900px, where the rail is simply there, and the checkbox is removed rather
   than hidden so it is not a tab stop that does nothing. */
.drawer, .drawer-toggle, .drawer-scrim { display: none; }
.drawer-toggle .drawer-close { display: none; }

/* --------------------------------------------------------------- footer */

.footer { margin-top: var(--space-7); padding: var(--space-4) 0 var(--space-6);
          border-top: 1px solid var(--color-line); display: flex; flex-wrap: wrap;
          gap: var(--space-4); align-items: center; font-size: var(--text-body-sm); color: var(--color-text-muted); }

/* -------------------------------------------------------------- sign in */

/* The screens reached before there is a session: the firm on one half, the
   fields on the other. The mark sits on the coloured half instead of in a bar
   above the form, so the column of fields starts at the top of the screen.

   The split is 46/54 rather than half and half: the half being read is the one
   being typed into, and it gets the room. */
.auth { min-height: 100vh; display: grid; grid-template-columns: minmax(0, 46fr) minmax(0, 54fr); }

/* The panel carries the mark and nothing else. */
.auth-aside {
  padding: var(--space-7);
  background: linear-gradient(155deg, var(--cgp-deep-800), var(--cgp-deep-900));
  color: var(--color-text-inverse);
}
.auth-aside .wordmark img { width: 40px; height: 40px; }
.auth-aside .wordmark-name { color: var(--color-text-inverse); font-size: 0.9375rem; }

.auth-main { display: flex; align-items: center; justify-content: center; padding: var(--space-8) var(--space-6); }
.auth-form { width: 100%; max-width: 25rem; }

/* -------------------------------------------------------------- journey */

.progress { height: 3px; background: var(--cgp-paper-200); border-radius: var(--radius-pill); overflow: hidden; flex-grow: 1; }
.progress > span { display: block; height: 100%; background: var(--cgp-deep-700);
                   transition: width var(--duration-base) var(--ease-out); }

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

/* Nothing appears or leaves abruptly. Anything that arrives fades up over the
   distance it travels, and anything that goes fades down over a shorter one:
   leaving is quicker than arriving, because the person has already decided.
   Every duration and distance is a token, so a reduced-motion request collapses
   the lot at the source rather than rule by rule. */

@keyframes cgp-step-in { from { opacity: 0; transform: translateY(var(--travel-step)); } to { opacity: 1; transform: none; } }
@keyframes cgp-step-in-back { from { opacity: 0; transform: translateY(calc(var(--travel-step) * -1)); } to { opacity: 1; transform: none; } }
@keyframes cgp-step-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(calc(var(--travel-step) * -0.7)); } }

/* Forward through the questionnaire, and back out of it. The direction is the
   only thing that tells someone on the recap screen that "Modifier" took them
   backwards rather than on to something new. */
.step-in { animation: cgp-step-in var(--duration-base) var(--ease-out) both; }
.step-in-back { animation: cgp-step-in-back var(--duration-base) var(--ease-out) both; }
.step-out { animation: cgp-step-out var(--duration-exit) var(--ease-exit) both; }

/* The arrival of a server-rendered page. One shot, on the content region only:
   the shell around it is the same shell it was on the previous page and moving
   it would say otherwise. */
.page-in { animation: cgp-step-in var(--duration-base) var(--ease-out) both; }

/* The arrival of a view of the case list, which is not a page arriving. The
   strip changes the table and nothing else on the screen, so the same rise is
   played on the pane alone: animating the content region would move a heading
   and a strip that did not change. */
.view-in { animation: cgp-step-in var(--duration-base) var(--ease-out) both; }

/* The region that holds the arriving content clips the travel. The rise starts
   the content a step below where it lands, and that step counts as scrollable
   overflow: without this, a page that fits the viewport grows a scrollbar for
   the length of the animation and loses it again. Both regions are sized by
   their content, so once the animation is over there is nothing outside them to
   clip. Clipped and not hidden, because hidden would make them scroll
   containers and strand the sticky action bar; vertical only, so a table too
   wide for the screen still scrolls sideways. */
.page, .shell, .auth { overflow-y: clip; }

/* There is no cross-document view transition here, and this note is why, so
   that nobody adds one back for the half of it that is appealing.

   One was declared, to carry the page being left into the one arriving rather
   than blink white in between. What it cost was the back office answering a
   click. A transition makes the page non-interactive from before it captures
   the outgoing state until the animation ends, and an element it captures is
   replaced meanwhile by a picture of itself, which the browser hit-tests no
   more than it hit-tests the element behind it. Capturing the root put the
   whole screen, rail included, in that state for the length of the fade on top
   of the time the next page took to arrive: clicking through the rail at a
   normal pace, every other click landed in that window and was lost.

   Capturing the content region alone gave the rail its clicks back and left two
   things behind. The departing content and the arriving content then sit
   stacked in one box, so the heading being left and the heading arriving are
   both legible, one written over the other, which every dissolve between two
   different texts in one place does. And hover is still not recomputed until
   the transition has ended and the pointer has moved again, so a rail walked
   through quickly draws no hover under a cursor that has not moved, which reads
   as a rail that has stopped responding. That last one is the browser's, not
   ours: it is an open question in the specification, and Safari and Chrome
   answer it differently.

   What the transition was wanted for, the screen not blanking between two
   pages, the browser already does without being asked: it holds the page being
   left until the next one paints, and the next one is served from this process
   in tens of milliseconds. The arrival is `.page-in`, in the document that
   arrives, which owes nothing to any of this. */

/* The bar a navigation runs under.

   That hold is also why a slow answer looks like nothing at all: the screen is
   complete, the pointer is back to an arrow, and the only available reading is
   that the click was lost. This is the one mark on the page that says it was
   not.

   It reports a wait and not a measurement. Nothing exposes how far a pending
   navigation has got, so the width decelerates towards an end it never reaches,
   and what ends it is the page arriving and destroying the document the bar was
   drawn in.

   Gold, at two pixels, on the top edge of the window: the accent is a rule here
   as it is everywhere else. It hangs off the body rather than off a shell,
   because the shells clip their vertical overflow and a fixed bar inside a
   clipped box is a clipped bar. */
.nav-bar {
  position: fixed; top: 0; left: 0; right: 0; height: 2px;
  z-index: calc(var(--z-overlay) + 1);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--duration-fast) var(--ease-out);
}
.nav-bar-run { opacity: 1; }
.nav-bar > span {
  display: block; width: 0; height: 100%;
  background: var(--color-line-accent);
  transition: width var(--duration-slow) linear;
}

/* A detail a yes opens up. The row grows from zero rather than being switched
   on, so the question above it does not jump. `display: none` cannot be
   animated, which is why this is a grid row and not a hidden attribute. */
.reveal { display: grid; grid-template-rows: 0fr; opacity: 0;
          transition: grid-template-rows var(--duration-slow) var(--ease-out),
                      opacity var(--duration-base) var(--ease-out); }
.reveal > * { overflow: hidden; min-height: 0; }
/* The row has to clip its content while it grows, but the focus ring of the
   field inside it is not content: it is the only thing telling a keyboard user
   where they are. Where the browser can clip with a margin, it gets one. */
@supports (overflow-clip-margin: 4px) {
  .reveal > * { overflow: clip; overflow-clip-margin: 4px; }
}
.reveal[data-open="true"] { grid-template-rows: 1fr; opacity: 1; }

/* The question area is exactly as tall as the question inside it, and the
   questions are not the same length: three hundred pixels separate the shortest
   from the longest. Its height is eased from one to the next so that the action
   bar and the notices below it stay where the hand left them, and clipped while
   it moves because the arriving question is at full height from the first frame.
   The two heights are pixel values the script sets; there is nothing to
   interpolate between otherwise. */
[data-role="panels"][data-sizing] { overflow-y: clip;
                                    transition: height var(--duration-slow) var(--ease-out); }

/* A message that was not there a moment ago. It settles into place; it never
   shoves the page. */
@keyframes cgp-notice-in { from { opacity: 0; transform: translateY(calc(var(--travel-step) * -0.6)); } to { opacity: 1; transform: none; } }
.notice-in { animation: cgp-notice-in var(--duration-base) var(--ease-out) both; }

/* ------------------------------------------------------------ dialogues */

/* The confirmation before something irreversible. It is a real element rather
   than the browser's own box, because that box cannot be given the typography
   of the thing it is asking about, and cannot be animated at all. */
.modal {
  width: min(var(--modal-width, 440px), calc(100vw - var(--space-6)));
  padding: 0; border: var(--border-hairline) solid var(--color-line);
  border-radius: var(--radius-lg);
  background: var(--color-surface-raised); color: var(--color-text);
  box-shadow: var(--shadow-overlay);
}
/* A question fits in 440 px. Ten recovery codes do not: at that width they wrap
   into a block of text nobody can track a line through. What is inside asks for
   the width it needs, rather than every dialogue paying for the widest one, and
   asks once for the whole of an enrolment rather than per step: a box that
   changed width between one step and the next would wobble. */
.modal:has(> .modal-wide:not([hidden])) { --modal-width: 580px; }
/* The veil carries a little blur where the browser has one, so the screen
   behind reads as out of reach rather than merely darkened. */
.modal::backdrop { background: rgba(2, 42, 57, 0); backdrop-filter: blur(0px); }
.modal[open] { animation: cgp-modal-in var(--duration-slow) var(--ease-out) both; }
.modal[open]::backdrop { animation: cgp-veil-in var(--duration-slow) var(--ease-out) both; }
/* Set by the script for the length of the exit, so the dialogue is still on
   screen while it leaves. */
.modal.is-closing { animation: cgp-modal-out var(--duration-exit) var(--ease-exit) both; }
.modal.is-closing::backdrop { animation: cgp-veil-out var(--duration-exit) var(--ease-exit) both; }

@keyframes cgp-modal-in {
  from { opacity: 0; transform: translateY(var(--travel-overlay)) scale(0.965); }
  to { opacity: 1; transform: none; }
}
@keyframes cgp-modal-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(calc(var(--travel-overlay) * 0.4)) scale(0.985); }
}
@keyframes cgp-veil-in {
  from { background: rgba(2, 42, 57, 0); backdrop-filter: blur(0px); }
  to { background: rgba(2, 42, 57, 0.32); backdrop-filter: blur(2px); }
}
@keyframes cgp-veil-out {
  from { background: rgba(2, 42, 57, 0.32); backdrop-filter: blur(2px); }
  to { background: rgba(2, 42, 57, 0); backdrop-filter: blur(0px); }
}

/* A dialogue that changes what it holds changes size. Left alone the box jumps
   from one size to the other, which reads as a second dialogue replacing the
   first rather than the same one going on to its next step. The script measures
   the old box, makes the change, and hands the two sizes over here. Only while
   it moves: the box is content sized the rest of the time. */
.modal.is-morphing { transition: width var(--duration-slow) var(--ease-out),
                                 height var(--duration-slow) var(--ease-out); }
/* Mid travel the box is smaller than what is in it. Clipping is what keeps the
   overflow from showing as a scrollbar that appears for a quarter of a second
   and then goes. */
.modal.is-morphing, .modal.is-morphing .modal-body { overflow: hidden; }

/* The body takes every pixel the dialogue has that the buttons do not, and is
   the one part that gives when there are not enough: while the box is being
   resized it is the body that is short, not the buttons, and the buttons stay
   on the bottom edge rather than floating above it. */
.modal-body { padding: var(--space-5) var(--space-5) var(--space-4); display: flex; flex-direction: column; gap: var(--space-3);
              flex: 1 1 auto; min-height: 0; overflow-y: auto; }
/* A dialogue that carries a form is taller than a question, and the browser
   caps a dialogue at the height of the viewport. The body is what scrolls, so
   the title and the buttons stay where they were. */
.modal[open] { display: flex; flex-direction: column; }
/* A dialogue with several steps holds them all and shows one. A step is a body
   and its own buttons, and the chain from the dialogue down to the step showing
   is one column that fills the height, so the buttons sit on the bottom edge
   whichever step is up. */
.modal > form, .modal-steps, .modal-pane { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.modal-title { font: 400 var(--text-display-sm) / 1.2 var(--font-display); letter-spacing: -0.015em; }
.modal-foot { display: flex; flex: none; flex-wrap: wrap; gap: var(--space-3); justify-content: flex-end;
              padding: var(--space-4) var(--space-5); border-top: 1px solid var(--color-line);
              background: var(--color-surface); }
/* The handle a thumb pulls the phone sheet down by. It exists only where the
   sheet does: on a pointer there is nothing to drag. */
.modal-grip { display: none; }

@keyframes cgp-draw { from { stroke-dashoffset: var(--draw-length); } to { stroke-dashoffset: 0; } }
/* The brand moment: the brass rule draws itself once, on arrival and on the
   confirmation that answers were sealed. Nowhere else. */
.frame-draw { stroke-dasharray: var(--draw-length); animation: cgp-draw var(--duration-deliberate) var(--ease-out) 120ms both; }

@media (prefers-reduced-motion: reduce) {
  /* The tokens already flatten every duration and distance. What is left is the
     handful of places where a 1 ms animation is still a flicker. */
  .step-in, .step-in-back, .step-out, .page-in, .view-in, .notice-in { animation: none; }
  .frame-draw { animation: none; stroke-dashoffset: 0; }
  .progress > span { transition: none; }
  .modal[open], .modal.is-closing { animation: none; }
}

/* ------------------------------------------------------------ responsive */

/* A rail does not fit a phone, and a table does not become a narrow table: it
   becomes a stack of cards. Both are layout changes, not a scale factor. */
@media (max-width: 900px) {
  /* The bar keeps the mark and the handle a thumb reaches at the far end, where
     the thumb already is. Everything else is in the drawer the handle opens. */
  /* The drawer comes in from the edge its handle is on, so the panel appears
     under the thumb that opened it rather than across the screen from it. */
  /* The drawer is sized by the inset it is given, so the two declarations that
     hold the desktop rail to the window are undone here. Both matter: the
     window height would hang the sheet 60px below the bottom edge, and
     flex-start makes a flex container's out-of-flow child shrink to its own
     content, which leaves a dark panel floating over a lit page. */
  .rail { position: fixed; inset: 60px 0 0 auto; z-index: var(--z-overlay);
          width: 84vw; max-width: 320px; height: auto; align-self: stretch;
          transform: translateX(100%); transition: transform var(--duration-slow) var(--ease-out);
          box-shadow: var(--shadow-overlay); overflow-y: auto;
          overscroll-behavior: contain; }
  .drawer:checked ~ .page .rail { transform: none; }

  /* The bar comes back to hold the mark and the handle, and the rail gives the
     mark up again: on a phone the rail is behind the handle most of the time. */
  .topbar-staff { display: flex; }
  .rail-head { display: none; }

  /* Tapping the page behind the drawer closes it, which is the gesture a phone
     expects and the only one available without scripting. */
  .drawer:checked ~ .page .drawer-scrim {
    display: block; position: fixed; inset: 60px 0 0 0;
    z-index: calc(var(--z-overlay) - 1); background: rgba(2, 42, 57, 0.32);
    animation: cgp-scrim-in var(--duration-base) var(--ease-out) both;
  }

  /* The checkbox is the control a keyboard reaches; the handle is what a thumb
     hits. So the checkbox is clipped rather than removed, and wears its focus
     ring on the handle. */
  .drawer { display: block; position: absolute; width: 1px; height: 1px;
            margin: -1px; overflow: hidden; clip-path: inset(50%); }
  .drawer-toggle { display: inline-flex; align-items: center; justify-content: center;
                   width: var(--hit-min); height: var(--hit-min); margin-right: calc(var(--space-3) * -1);
                   border-radius: var(--radius-md); cursor: pointer; }
  .drawer:focus-visible ~ .page .drawer-toggle { outline: 2px solid var(--color-focus); outline-offset: 2px; }
  .drawer:checked ~ .page .drawer-toggle .drawer-open { display: none; }
  .drawer:checked ~ .page .drawer-toggle .drawer-close { display: inline-flex; }

  .main { padding: var(--space-5) var(--space-4) var(--space-8); }
  .wrap-wide { padding: 0 var(--space-4); }

  /* The sign-in halves stack, and the coloured one becomes a band: the rows are
     named so the extra height goes to the form rather than being shared out. */
  .auth { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .auth-aside { padding: var(--space-4); }
  .auth-main { align-items: flex-start; padding: var(--space-6) var(--space-4) var(--space-8); }
}

@keyframes cgp-scrim-in { from { opacity: 0; } to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .rail { transition: none; }
  .drawer:checked ~ .page .drawer-scrim { animation: none; }
}

@media (max-width: 640px) {
  .display-xl { font-size: var(--text-display-md); }
  .display-lg { font-size: var(--text-display-md); }
  .wrap { padding: 0 var(--space-4); }

  /* Each row becomes a card. The header row is dropped and every cell carries
     its own label, because a column heading twelve rows up is not a label. */
  .table, .table tbody, .table tr, .table td { display: block; width: 100%; }
  .table { border: none; background: transparent; }
  .table thead { display: none; }
  .table tr { background: var(--color-surface-raised); border: var(--border-hairline) solid var(--color-line);
              border-radius: var(--radius-lg); padding: var(--space-4); margin-bottom: var(--space-3); }
  .table td { border: none; padding: 0 0 var(--space-2); }
  .table td:last-child { padding-bottom: 0; }
  .table td[data-label]::before { content: attr(data-label) " "; font-size: var(--text-label);
    letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--color-text-muted); display: block;
    margin-bottom: var(--space-1); }
  /* A row action is a small button among columns. In a card it is the only
     thing there is to press, and a thumb is not a pointer. */
  .table .btn-sm { height: var(--hit-min); padding: 0 var(--space-4); }

  /* The primary action leaves the flow and sits where a thumb reaches it. */
  .action-bar { position: sticky; bottom: 0; background: var(--color-surface-raised);
                border-top: 1px solid var(--color-line);
                padding: var(--space-3) var(--space-4) var(--space-6);
                margin: var(--space-5) calc(var(--space-4) * -1) 0;
                display: flex; flex-wrap: wrap; gap: var(--space-3); }
  .action-bar .btn { height: var(--control-touch); flex-grow: 1; }
  .action-bar .btn-ghost, .action-bar .btn-secondary { flex-grow: 0; }
  /* The spacer that holds the two buttons at opposite ends of a wide bar is
     what pushes one of them off a narrow one: at 360px there is no room
     between "Question précédente" and "Continuer" to give away. Narrower still
     and the labels do not fit on one line either, so the bar wraps and the
     button that goes on takes the second line whole. */
  .action-bar .grow { display: none; }
  .choice { min-height: 60px; font-size: 1.0625rem; }

  /* A dialogue in the middle of a phone screen is out of reach and covers what
     it is asking about. It becomes a sheet that rises from the bottom edge. */
  .modal { width: 100%; max-width: none; margin: auto auto 0;
           max-height: calc(100% - var(--space-7));
           border-radius: var(--radius-lg) var(--radius-lg) 0 0; border-bottom: 0; }
  .modal[open] { animation: cgp-sheet-in var(--duration-slow) var(--ease-soft) both; }
  .modal-foot { padding-bottom: var(--space-6); }
  .modal-foot .btn { flex-grow: 1; height: var(--control-touch); }

  /* The sheet is pulled down by its handle. The handle takes the touch itself,
     so a drag never becomes a scroll of the body behind it, and it is drawn
     wide enough to be aimed at rather than hit by luck. */
  .modal-grip { display: flex; align-items: center; justify-content: center; flex: none;
                height: var(--space-6); touch-action: none; }
  .modal-grip::before { content: ""; width: 40px; height: 4px; border-radius: 999px;
                        background: var(--color-line-strong); }

  /* While the finger is down the sheet is where the finger put it, which means
     the arrival animation has to let go of the transform it is holding. */
  .modal.is-dragging { animation: none; transform: translateY(var(--sheet-drag, 0px)); }
  /* The release: back to the edge it was resting on, or on out. */
  .modal.is-settling { transition: transform var(--duration-slow) var(--ease-soft); }
  /* Last, so the exit wins over the hold the drag has on the transform. */
  .modal.is-closing { animation: cgp-sheet-out var(--duration-exit) var(--ease-exit) both; }

  @keyframes cgp-sheet-in { from { transform: translateY(100%); } to { transform: none; } }
  /* Leaves from wherever the finger left it, so a drag that turns into a
     dismissal is one movement rather than a snap back and then an exit. */
  @keyframes cgp-sheet-out { from { transform: translateY(var(--sheet-drag, 0px)); } to { transform: translateY(100%); } }
}

/* ---------------------------------------------------- answers, on screen */

/*
 * The questionnaire, read in the back office.
 *
 * Every class here is prefixed "answer-". That is not decoration: an early
 * version reused ".field", which in this same stylesheet is a 44px form input,
 * so every answer rendered as an empty text box with its label on the border
 * and the value clipped. A reading surface and an input surface must not share
 * a name.
 *
 * The dossier is arranged by outcome, not by form order: what was declared,
 * expanded, then what was ruled out, as one line per question. See the view for
 * why, and for what pays for the reordering.
 *
 * Two earlier layouts are worth remembering so they are not tried again. A
 * narrow paper sheet on screen was a picture of a PDF in a back office. A card
 * per answer failed on the commonest dossier of all, the one with nothing
 * declared: twelve cards promising something to read and holding nothing, of a
 * width that changed on every row. A card promises content; a negative answer
 * has none, so a negative answer is a line.
 */

/* No max-width. The reading surface is the width of the main column. */
.answer-screen { display: flex; flex-direction: column; gap: var(--space-5); }

/* Both rows here lead with a mark, and a flex child is allowed to be squeezed
   below its own width: on a phone the tick beside "rien n'a été déclaré" was
   drawn eight pixels wide. Declared once rather than on each of the two. */
.answer-none svg, .answer-item-empty svg { flex: none; }

/* -- the band of facts at the head of the dossier */

.answer-band {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--space-3);
}

.answer-tile {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-4);
  background: var(--color-surface-raised);
  border: var(--border-hairline) solid var(--color-line);
  border-radius: var(--radius-lg);
}
.answer-tile-label {
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.answer-tile-value { font-size: var(--text-body-lg); overflow-wrap: anywhere; }
.answer-tile-accent { background: var(--cgp-brass-100); border-color: var(--cgp-brass-200); }

/* -- a block: declared, pending, out of form, ruled out */

/*
 * Every block sits on the same surface, with the same inset.
 *
 * That is what aligns the headings: while only the declarations had a panel,
 * "Déclaré" started one padding-width in from the column edge and "Écarté"
 * started at it, so the two titles did not share a vertical.
 */
.answer-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5) var(--space-5);
  background: var(--color-surface-raised);
  border: var(--border-hairline) solid var(--color-line);
  border-radius: var(--radius-lg);
}

.answer-block-head { display: flex; align-items: center; gap: var(--space-3); }
.answer-block-title {
  margin: 0;
  font: 400 var(--text-display-sm) / 1.2 var(--font-display);
  letter-spacing: -0.015em;
}
.answer-block-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
  font-size: var(--text-body-sm);
  font-weight: var(--weight-semibold);
  font-variant-numeric: var(--numeric-tabular);
}
.answer-count-yes { background: var(--cgp-state-waiting-bg); color: var(--cgp-state-waiting); }
.answer-count-alert { background: var(--cgp-state-blocked-bg); color: var(--cgp-state-blocked); }
.answer-block-rule { flex-grow: 1; height: 1px; background: var(--color-line); }

.answer-block-note {
  margin: 0;
  font-size: var(--text-body-sm);
  color: var(--color-text-muted);
  max-width: var(--measure-prose);
}

/* The declarations are the reason the screen exists, so the block that holds
   them is the only one marked. Its inset is the same, so the heading still
   shares the vertical with the others. */
.answer-block-declared { gap: 0; border-color: var(--cgp-brass-200); }
.answer-block-declared .answer-block-head { padding-bottom: var(--space-2); }

/* -- one declaration */

.answer-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding-block: var(--space-5);
  border-bottom: var(--border-hairline) solid var(--color-line);
  min-width: 0;
}
.answer-item:last-child { border-bottom: none; padding-bottom: 0; }

.answer-item-head { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.answer-item-section {
  font-size: var(--text-label);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--color-text-accent);
}

/*
 * The question's number in the insurer's form.
 *
 * This is what makes grouping by outcome acceptable: the screen no longer
 * follows the form's order, so every question says where it is on the form a
 * expert keys the answers into.
 */
.answer-rank {
  font-size: var(--text-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--cgp-ink-400);
  white-space: nowrap;
}

.answer-item-question {
  margin: 0;
  line-height: var(--leading-snug);
  color: var(--cgp-ink-700);
  max-width: 92ch;
}

.answer-item-detail { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }

.answer-item-empty {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-size: var(--text-body-sm);
  color: var(--cgp-state-blocked);
}

/* -- small facts, side by side */

.answer-facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-6);
  margin: 0;
}
.answer-fact { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.answer-fact dt {
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--cgp-ink-400);
}
.answer-fact dd { margin: 0; overflow-wrap: anywhere; }

/* -- prose, which is where the medical content is */

.answer-note { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.answer-note-label {
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--cgp-ink-400);
}
.answer-note-text {
  margin: 0;
  font: 400 var(--text-body-lg) / 1.6 var(--font-display);
  color: var(--color-text);
  max-width: 76ch;
  text-wrap: pretty;
  /* Free text is the client's, so it can carry an unbroken term longer than the
     column. It wraps rather than widening the block. */
  overflow-wrap: anywhere;
}

.answer-declared {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-size: var(--text-body-sm);
  font-weight: var(--weight-medium);
  color: var(--cgp-state-positive);
}
.answer-declared-no { color: var(--cgp-state-blocked); }

/* -- the lines: a question that was asked and answered no */

.answer-lines { list-style: none; margin: 0; padding: 0; }

.answer-line {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr) auto;
  gap: var(--space-4);
  align-items: baseline;
  padding-block: var(--space-2);
  border-bottom: var(--border-hairline) solid var(--cgp-paper-100);
}
.answer-line:last-child { border-bottom: none; }
.answer-line-question { font-size: var(--text-body-sm); color: var(--color-text-muted); }
.answer-line-mark { color: var(--cgp-state-positive); display: flex; }

/* Nothing declared, which is the ordinary dossier and deserves a sentence
   rather than a list the reader has to count. */
.answer-none {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-3) 0 0;
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-md);
  background: var(--cgp-state-positive-bg);
  color: var(--cgp-state-positive);
  font-weight: var(--weight-medium);
}

/*
 * The questionnaire an administrator sees: the same markup, under a veil.
 *
 * The veil is presentation only. What it covers is the form's own questions and
 * a fixed placeholder, because nothing was decrypted for this render, so the
 * blur hides no answer that inspecting the page would reveal.
 */
.answer-sealed { filter: blur(6px); user-select: none; pointer-events: none; }
.answer-sealed-notice {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
  font-size: var(--text-body-sm);
}
.answer-sealed-notice svg { flex: none; color: var(--color-text-brand); }

/* A choice that is shown and may not be made: the verdict, on a screen opened by
   a role that does not conclude. */
.choice:has(input:disabled),
.choice:has(input:disabled):hover {
  opacity: 0.42;
  cursor: not-allowed;
  border-color: var(--cgp-paper-300);
  transform: none;
}

/* A key the current form no longer carries, shown as it came. */
.answer-raw {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-family: var(--font-mono);
  font-size: var(--text-body-sm);
  margin: 0;
  color: var(--color-text-muted);
}

.answer-warning {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--cgp-state-waiting-bg);
  color: var(--cgp-state-waiting);
  font-size: var(--text-body);
  margin: 0;
}

/* -- what belongs to one medium and not the other */

.print-only { display: none; }

/* ----------------------------------------------------- answers, on a phone */

@media (max-width: 640px) {
  .answer-screen { gap: var(--space-4); }
  .answer-band { grid-template-columns: minmax(0, 1fr); gap: var(--space-2); }
  .answer-tile { padding: var(--space-3) var(--space-4); }

  .answer-block-title { font-size: var(--text-display-md); }
  .answer-block { padding: var(--space-3) var(--space-4) var(--space-4); }
  .answer-item { padding-block: var(--space-4); gap: var(--space-3); }
  .answer-facts { gap: var(--space-3) var(--space-5); }

  /* The number moves above the question rather than taking a column of a phone. */
  .answer-line {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--space-1) var(--space-3);
    padding-block: var(--space-3);
  }
  .answer-line .answer-rank { grid-column: 1 / -1; }

  /* The band's buttons stack and take the width rather than sitting as halves
     on a phone. Scoped to the band: the rest of the back office keeps a button
     at its own width. */
  .case-band-acts { flex-direction: column; align-items: stretch; width: 100%; }
  .case-band-acts .btn {
    height: var(--control-touch);
    width: 100%;
    justify-content: center;
  }
  /* The verdict is two full width choices and a commit, not three chips. */
  .case-close-act { flex-direction: column; align-items: stretch; }
  .case-close-act .btn { height: var(--control-touch); }
  /* What is owed is one act under another, each at the width of the thumb that
     presses it. A telephone number is the one thing on this screen a person
     reaches for while holding the phone in the other hand. */
  .case-next-act { flex-direction: column; align-items: stretch; width: 100%; }
  .case-next-act .btn { height: var(--control-touch); width: 100%; justify-content: center; }
}

/* ------------------------------------------------------- answers, on paper */

@media print {
  .rail, .action-bar, .drawer-toggle, .btn, .topbar, .no-print { display: none !important; }

  /*
   * The printed dossier keeps the screen's structure and loses the interface.
   * Screen and paper must show the same dossier in the same order, or an expert
   * holding both finds two different documents; so the blocks stay, and what
   * goes is the fills, the radii, the panels and the tiles.
   *
   * Authored against the @page rule below rather than the viewport, with the
   * body face at 10.5pt so the prose clears the 12pt floor a printed
   * questionnaire is read at.
   */
  @page { margin: 18mm 16mm; }

  body { background: #fff; color: #000; font-size: 10.5pt; }
  .page, .shell, .main { display: block; padding: 0; margin: 0; max-width: none; min-height: 0; }

  .print-only { display: block; }

  .answer-paper { margin-bottom: 10pt; }
  .answer-paper-note {
    margin: 6pt 0 0;
    font-size: 7.5pt;
    line-height: 1.4;
    color: #000;
    max-width: 82ch;
  }

  .answer-masthead {
    display: flex;
    align-items: flex-start;
    gap: 16pt;
    padding-bottom: 8pt;
    border-bottom: 1.5pt solid #000;
  }
  .answer-masthead-who { display: flex; flex-direction: column; gap: 3pt; min-width: 0; }
  .answer-masthead-name {
    margin: 0;
    font: 400 18pt / 1.2 var(--font-display);
    letter-spacing: -0.015em;
  }
  .answer-masthead-case {
    display: flex;
    flex-direction: column;
    gap: 2pt;
    margin-left: auto;
    text-align: right;
    flex-shrink: 0;
  }
  .answer-masthead .caps { color: #3a3a3a; }

  .answer-screen { display: block; }

  /* The dossier is one block on the case screen, and the space that separates it
     from the administrative panels below belongs to the screen alone. */
  .case-dossier { margin: 0 !important; }

  /* The band becomes a line of facts, not a row of boxes. */
  .answer-band {
    display: flex;
    gap: 20pt;
    flex-wrap: wrap;
    padding-bottom: 8pt;
    border-bottom: 0.5pt solid #000;
  }
  .answer-tile, .answer-tile-accent {
    display: flex;
    padding: 0;
    background: none;
    border: none;
    border-radius: 0;
  }
  .answer-tile-label { color: #3a3a3a; }
  .answer-tile-value { font-size: 10.5pt; }

  .answer-block, .answer-block-declared {
    display: block;
    margin-top: 14pt;
    padding: 0;
    background: none;
    border: none;
    border-radius: 0;
  }
  .answer-block-head { display: flex; gap: 8pt; padding: 0 0 2pt; }
  .answer-block-title { font-size: 14pt; }
  .answer-block-count, .answer-count-yes, .answer-count-alert {
    background: none;
    color: #000;
    min-width: 0;
    height: auto;
    padding: 0;
    font-size: 12pt;
  }
  .answer-block-rule { background: #000; }
  .answer-block-note { color: #3a3a3a; font-size: 8pt; margin-bottom: 4pt; }

  .answer-item {
    display: block;
    padding: 6pt 0;
    border-bottom: 0.4pt solid #767676;
  }
  .answer-item:last-child { border-bottom: none; }
  .answer-item-head { display: flex; gap: 10pt; }
  .answer-item-section, .answer-rank { color: #000; }
  .answer-item-question { color: #000; margin-top: 3pt; max-width: none; }
  .answer-item-detail { display: block; margin-top: 5pt; }
  .answer-facts { gap: 5pt 18pt; padding: 0; border: none; }
  .answer-fact dt, .answer-note-label { color: #3a3a3a; }
  .answer-note { margin-top: 5pt; }
  .answer-note-text { color: #000; font-size: 10.5pt; max-width: 64ch; }
  .answer-item-empty, .answer-declared { color: #000; }

  .answer-line {
    grid-template-columns: 52pt minmax(0, 1fr) auto;
    gap: 10pt;
    padding-block: 2.5pt;
    border-bottom: 0.3pt solid #b0b0b0;
  }
  .answer-line-question { color: #000; font-size: 9.5pt; }
  .answer-line-mark { color: #000; }

  .answer-none {
    display: block;
    margin: 4pt 0 0;
    padding: 4pt 0 0;
    background: none;
    border-top: 0.5pt solid #000;
    border-radius: 0;
    color: #000;
  }
  .answer-none svg { display: none; }

  .answer-raw { color: #000; }
  .answer-warning { border: 0.8pt solid #000; background: none; color: #000; margin-top: 8pt; }

  /* A question must not be cut from the answer it belongs to. */
  .answer-item { break-inside: avoid; page-break-inside: avoid; }
  .answer-block-head { break-after: avoid; page-break-after: avoid; }
  .answer-masthead, .answer-band { break-after: avoid; page-break-after: avoid; }
}

/*
 * The enrolment code.
 *
 * White ground and a fixed size whatever the page's theme is: a camera reads
 * contrast, and a code tinted to match a dark page is a code that half the
 * phones in the room will not pick up.
 */
.qr {
  background: #ffffff;
  padding: var(--space-3);
  border-radius: var(--radius-md);
  width: max-content;
  max-width: 100%;
  line-height: 0;
}

.qr svg {
  display: block;
  width: 208px;
  height: 208px;
  max-width: 100%;
}
