/* =============================================================================
   PalladiumSign - design system
   -----------------------------------------------------------------------------
   One accent colour, warm paper neutrals, a serif wordmark. The product signs
   and seals documents, so it borrows from stationery rather than from dashboards.
   Light and dark are both defined on :root so nothing is left to the browser.
   ============================================================================= */

:root {
    color-scheme: light;

    --paper:        #f7f5f2;
    --paper-raised: #ffffff;
    --paper-sunken: #efece7;
    --ink:          #191b1c;
    --ink-soft:     #52585c;
    --ink-faint:    #63696e;   /* secondary text: >= 4.5:1 on all three papers and on --seal-tint */
    --ink-hush:     #8b9196;   /* the old faint, kept for decoration only: placeholders, dots, rules */
    --line:         #ddd8d1;
    --line-strong:  #c6c0b7;
    --line-control: #8f877c;   /* the edge of something you operate: >= 3:1 on raised and on sunken */

    --seal:         #a2543a;
    --seal-hover:   #8c452f;
    --seal-tint:    #f6e9e3;
    --on-seal:      #ffffff;   /* text on --seal and --seal-hover; the dark seal is lighter and needs ink */
    --on-warn:      #ffffff;   /* text on --warn, same story */

    --graphite:     #1d2124;
    --graphite-2:   #2a2f33;

    /* Five state colours, each meaning exactly one thing. More than that and nobody learns them.
         ok    done, nothing to do
         info  moving along, waiting on somebody else, nothing for you to do
         warn  needs you, or a deadline coming
         bad   stopped: refused, blocked, failed
         mute  not started, or over and filed away                                            */
    --ok:           #1f6f4a;
    --ok-tint:      #e3f2ea;
    --warn:         #8a5a12;
    --warn-tint:    #fbf0dc;
    --bad:          #9b2c22;
    --bad-tint:     #fbe7e4;
    --info:         #1f5566;
    --info-tint:    #e6eef1;

    --radius:       10px;
    --radius-sm:    6px;
    --shadow:       0 1px 2px rgba(24, 26, 27, .05), 0 8px 24px rgba(24, 26, 27, .06);

    --sans: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
    --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif;
    --mono: ui-monospace, "Cascadia Mono", "Consolas", "Courier New", monospace;
}

/* Dark palette, in ONE place.
   The theme is an attribute on <html> that is ALWAYS present: an inline script in the head
   resolves the stored preference (light / dark / system) before the first paint and writes it,
   so there is no flash and no second copy of these values under a media query. Two copies of a
   palette drift apart, and the one that drifts is always the one nobody is looking at. */
:root[data-theme="dark"] {
    color-scheme: dark;

    --paper:        #121415;
    --paper-raised: #1a1d1f;
    --paper-sunken: #0d0f10;
    --ink:          #e9e6e2;
    --ink-soft:     #a9aeb2;
    --ink-faint:    #858b90;
    --ink-hush:     #767c81;
    --line:         #2b2f32;
    --line-strong:  #3b4145;
    --line-control: #626a70;

    --seal:         #c9765a;
    --seal-hover:   #d98a6d;
    --seal-tint:    #2c1e19;
    --on-seal:      #121415;
    --on-warn:      #121415;

    --graphite:     #0d0f10;
    --graphite-2:   #171a1c;

    --ok:           #4caf85;
    --ok-tint:      #12241c;
    --warn:         #d09a3c;
    --warn-tint:    #241d10;
    --bad:          #e07a6e;
    --bad-tint:     #2a1615;
    --info:         #6fb3c9;
    --info-tint:    #12242b;

    --shadow:       0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px rgba(0, 0, 0, .35);
}

/* The paper. The editor's page and the signing page paint a white sheet whatever the theme,
   because a contract is white - so nothing drawn ON the sheet may follow the theme either: in
   dark mode --ink is nearly white and a field's value vanished on the page (1.06:1). These are
   fixed on purpose, have no dark copy, and every rule that draws on the sheet uses them.
   Checked once against #fff: the text tokens are >= 4.5:1, the line token >= 3:1. */
:root {
    --paper-white: #fff;
    --paper-ink:   #191b1c;
    --paper-seal:  #a2543a;
    --paper-ok:    #1f6f4a;
    --paper-warn:  #8a5a12;
    --paper-faint: #6b7176;
    --paper-line:  #8b9196;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    background: var(--paper);
    color: var(--ink);
    font-family: var(--sans);
    font-size: 15px;
    line-height: 1.55;
}

h1, h2, h3, h4 { margin: 0 0 .4em; line-height: 1.2; font-weight: 600; }
h1 { font-size: 1.6rem; letter-spacing: -.01em; }
h2 { font-size: 1.2rem; }
h3 { font-size: 1rem; }
p  { margin: 0 0 1em; }
a  { color: var(--seal); text-decoration: none; }
a:hover { text-decoration: underline; }

code, .mono { font-family: var(--mono); font-size: .86em; }

/* Focus you can see. One ring, in the accent, two pixels off the edge, on everything the keyboard
   can land on. :where() keeps it at zero specificity so a control that draws its own ring (the
   textarea on the paper, the drop zone) still wins. */
:where(a, button, summary, input, select, textarea, [tabindex]:not([tabindex="-1"])):focus-visible {
    outline: 2px solid var(--seal);
    outline-offset: 2px;
}

/* Routes.razor moves focus to the h1 after every navigation so a screen reader announces the new
   page. The move stays; the rectangle Chrome drew around every title on every load goes. */
h1:focus, h1:focus-visible { outline: none; }

/* ------------------------------------------------------------------ wordmark */

.brand {
    display: inline-flex;
    align-items: center;
    gap: .6rem;
    text-decoration: none;
    color: inherit;
}

.brand:hover { text-decoration: none; }

.brand-seal {
    width: 30px;
    height: 30px;
    flex: 0 0 auto;
    border-radius: 50%;
    border: 1.5px solid var(--seal);
    color: var(--seal);
    display: grid;
    place-items: center;
    font-family: var(--serif);
    font-size: 13px;
    letter-spacing: .02em;
}

.brand-name {
    font-family: var(--serif);
    font-size: 1.12rem;
    letter-spacing: .01em;
}

.brand-name b { font-weight: 600; }
.brand-name span { color: var(--ink-soft); }

.brand-large .brand-seal { width: 44px; height: 44px; font-size: 17px; }
.brand-large .brand-name { font-size: 1.5rem; }

/* -------------------------------------------------------------------- shell */

.shell { min-height: 100vh; display: flex; flex-direction: column; }

.topbar {
    background: var(--paper-raised);
    border-bottom: 1px solid var(--line);
    padding: .4rem 1.25rem;
    display: flex;
    align-items: center;
    gap: 1.5rem;
    min-height: 58px;
    flex-wrap: wrap;
}

.topbar nav { display: flex; flex-wrap: wrap; gap: .25rem; margin-right: auto; }

.topbar nav a {
    padding: .4rem .7rem;
    border-radius: var(--radius-sm);
    color: var(--ink-soft);
    font-size: .92rem;
}

.topbar nav a:hover { background: var(--paper-sunken); color: var(--ink); text-decoration: none; }

.topbar nav a.active {
    color: var(--ink);
    background: var(--paper-sunken);
    box-shadow: inset 0 -2px 0 var(--seal);
}

/* On a phone the links wrap under the wordmark. Tighter, so the bar takes two rows, not three. */
@media (max-width: 760px) {
    .topbar nav a { padding: .45rem .55rem; font-size: .88rem; }
}

.topbar-user { display: flex; align-items: center; gap: .75rem; font-size: .88rem; }
.topbar-user .who { text-align: right; line-height: 1.25; }
.topbar-user .who strong { display: block; font-weight: 600; }
.topbar-user .who span { color: var(--ink-faint); font-size: .82rem; }

/* The name became a link to "your details". It has to keep looking like a label rather than turning
   blue and underlined in the middle of the header - the hover is what says it can be clicked. */
a.who { color: inherit; text-decoration: none; border-radius: var(--radius-sm); padding: .15rem .3rem; }
a.who:hover { background: var(--paper-raised); }
a.who:hover strong { color: var(--seal); }

.content { flex: 1 1 auto; width: 100%; max-width: 1080px; margin: 0 auto; padding: 1.75rem 1.25rem 4rem; }

.page-head { margin-bottom: 1.5rem; }
.page-head p { color: var(--ink-soft); margin: 0; }

/* -------------------------------------------------------------------- cards */

.card {
    background: var(--paper-raised);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 1.15rem 1.25rem;
    box-shadow: var(--shadow);
}

.card + .card { margin-top: 1rem; }
.card h2, .card h3 { margin-bottom: .75rem; }

.grid { display: grid; gap: 1rem; }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }

.stat { font-family: var(--serif); font-size: 1.8rem; line-height: 1.1; font-variant-numeric: tabular-nums; }
.stat-label { color: var(--ink-faint); font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; }

/* --------------------------------------------------------------- definitions */

.facts { margin: 0; display: grid; grid-template-columns: max-content 1fr; gap: .45rem 1.25rem; }
.facts dt { color: var(--ink-faint); font-size: .85rem; }
.facts dd { margin: 0; font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------------------- badges */

.badge {
    display: inline-block;
    padding: .12rem .5rem;
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .02em;
    border: 1px solid transparent;
}

.badge-ok   { background: var(--ok-tint);   color: var(--ok);   border-color: color-mix(in srgb, var(--ok) 25%, transparent); }
.badge-warn { background: var(--warn-tint); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 25%, transparent); }
.badge-bad  { background: var(--bad-tint);  color: var(--bad);  border-color: color-mix(in srgb, var(--bad) 25%, transparent); }
.badge-mute { background: var(--paper-sunken); color: var(--ink-soft); border-color: var(--line); }

/* ------------------------------------------------------------------- notices */

.notice {
    border: 1px solid var(--line);
    border-left: 3px solid var(--ink-faint);
    border-radius: var(--radius-sm);
    padding: .8rem 1rem;
    margin-bottom: 1.25rem;
    background: var(--paper-raised);
}

.notice-warn { border-left-color: var(--warn); background: var(--warn-tint); color: var(--warn); }
.notice-bad  { border-left-color: var(--bad);  background: var(--bad-tint);  color: var(--bad); }
.notice-ok   { border-left-color: var(--ok);   background: var(--ok-tint);   color: var(--ok); }
.notice p:last-child { margin-bottom: 0; }
.notice a { color: inherit; text-decoration: underline; }

/* --------------------------------------------------------------------- forms */

.field { margin-bottom: 1rem; }

.field label {
    display: block;
    font-size: .85rem;
    font-weight: 600;
    color: var(--ink-soft);
    margin-bottom: .3rem;
}

.input {
    width: 100%;
    padding: .6rem .75rem;
    font: inherit;
    color: var(--ink);
    background: var(--paper-raised);
    border: 1px solid var(--line-control);
    border-radius: var(--radius-sm);
    transition: border-color .12s ease;
}

/* The old ring was a 22% tint of the seal: 1.4:1, as good as none. The ring is now the same
   outline everything focusable gets; the border takes the accent as well. */
.input:focus { border-color: var(--seal); }
.input:focus-visible { outline: 2px solid var(--seal); outline-offset: 2px; box-shadow: none; }

.input::placeholder { color: var(--ink-hush); }

.check { display: flex; align-items: center; gap: .5rem; font-size: .9rem; color: var(--ink-soft); }
.check input { accent-color: var(--seal); width: 1rem; height: 1rem; }

.hint { color: var(--ink-faint); font-size: .82rem; margin: .35rem 0 0; }

.validation-message, .validation-errors { color: var(--bad); font-size: .85rem; margin: .3rem 0 0; }
.validation-errors { list-style: none; padding: 0; }

/* ------------------------------------------------------------------- buttons */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    padding: .58rem 1.1rem;
    font: inherit;
    font-weight: 600;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    cursor: pointer;
    transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}

.btn-primary { background: var(--seal); color: var(--on-seal); }
.btn-primary:hover { background: var(--seal-hover); color: var(--on-seal); text-decoration: none; }

.btn-quiet { background: transparent; border-color: var(--line-control); color: var(--ink-soft); }
.btn-quiet:hover { background: var(--paper-sunken); color: var(--ink); text-decoration: none; }

.btn-link { background: none; border: none; padding: .3rem .1rem; color: var(--seal); cursor: pointer; font: inherit; }
.btn-link:hover { text-decoration: underline; }

.btn-block { width: 100%; }

.btn:disabled { opacity: .55; cursor: not-allowed; }

/* --------------------------------------------------------------------- table */

.table { width: 100%; border-collapse: collapse; font-size: .92rem; }
.table th, .table td { text-align: left; padding: .6rem .75rem; border-bottom: 1px solid var(--line); }
.table td { font-variant-numeric: tabular-nums; }
.table th { color: var(--ink-faint); font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 600; }
.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr.is-current { background: var(--seal-tint); }
.table-scroll { overflow-x: auto; }

/* ---------------------------------------------------------------- auth pages */

.auth {
    min-height: 100vh;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.auth-aside {
    background: var(--graphite);
    color: #e9e6e2;
    padding: 3rem;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    background-image: radial-gradient(circle at 85% 15%, var(--graphite-2), transparent 55%);
}

.auth-aside .brand-name span { color: #9aa1a6; }
.auth-aside .brand-seal { border-color: var(--seal); color: var(--seal); }

.auth-pitch { max-width: 26rem; }

.auth-pitch h1 {
    font-family: var(--serif);
    font-weight: 500;
    font-size: 2rem;
    line-height: 1.25;
    margin-bottom: .75rem;
}

.auth-pitch p { color: #a9aeb2; margin: 0; }

.auth-pitch ul { list-style: none; padding: 0; margin: 1.5rem 0 0; color: #c3c8cb; font-size: .92rem; }
.auth-pitch li { padding-left: 1.1rem; position: relative; margin-bottom: .4rem; }
.auth-pitch li::before { content: ""; position: absolute; left: 0; top: .62em; width: .4rem; height: .4rem; border-radius: 50%; background: var(--seal); }

.auth-foot { color: #767c81; font-size: .8rem; }

.auth-main { display: grid; place-items: center; padding: 2rem 1.5rem; }
.auth-form { width: 100%; max-width: 22.5rem; }
.auth-form h2 { font-size: 1.35rem; margin-bottom: .25rem; }
.auth-form > p { color: var(--ink-soft); margin-bottom: 1.5rem; }
.auth-form .btn-primary { margin-top: .5rem; }

/* The quiet way out from under a sign-in form: forgotten password, back to sign in. Its own class
   and not .auth-aside, which is the dark panel of the layout - reusing that name here would paint
   a graphite block under the form. */
.auth-link {
    margin: 1.25rem 0 0;
    text-align: center;
    font-size: .88rem;
    color: var(--ink-soft);
}

.auth-link a { color: var(--ink-soft); text-decoration: underline; text-underline-offset: 2px; }
.auth-link a:hover { color: var(--seal); }

/* A form that sits inside a table cell and must not add a line of its own: the role selector on a
   team row. */
.inline-form { display: inline-flex; align-items: center; gap: .35rem; margin: 0; }

/* Something the reader has to copy by hand or read out: a one-time link. Wraps rather than
   overflows, and selects in one gesture. */
.selectable {
    user-select: all;
    word-break: break-all;
    padding: .6rem .7rem;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
}

@media (max-width: 860px) {
    .auth { grid-template-columns: 1fr; }
    .auth-aside { padding: 2rem 1.5rem; gap: 2rem; }
    .auth-pitch h1 { font-size: 1.6rem; }
    .auth-foot { display: none; }
}

/* ------------------------------------------------------- blazor error banner */

#blazor-error-ui {
    display: none;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1000;
    padding: .8rem 1.25rem;
    background: var(--bad-tint);
    color: var(--bad);
    border-top: 1px solid var(--bad);
    font-size: .9rem;
}

#blazor-error-ui .dismiss { cursor: pointer; float: right; }

/* =============================================================================
   Public front page
   -----------------------------------------------------------------------------
   The only screen a stranger sees. It has to say what the product is before it
   asks for anything, so it gets room the application screens do not need.
   ============================================================================= */

.shell-public { min-height: 100vh; display: flex; flex-direction: column; }

.topbar-public nav { margin-left: auto; margin-right: 1.5rem; }

.public-body {
    flex: 1;
    width: 100%;
    max-width: 1120px;
    margin: 0 auto;
    padding: 3rem 1.5rem 4rem;
    display: flex;
    flex-direction: column;
    gap: 2.5rem;
}

.public-foot {
    border-top: 1px solid var(--line);
    padding: 1.25rem 1.5rem;
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    color: var(--ink-faint);
    font-size: .82rem;
}

.hero {
    display: grid;
    grid-template-columns: 1.15fr .85fr;
    gap: 2.5rem;
    align-items: start;
}

.hero h1 {
    font-family: var(--serif);
    font-size: clamp(2rem, 4.2vw, 3rem);
    line-height: 1.12;
    margin: .35rem 0 1rem;
    letter-spacing: -.015em;
}

.eyebrow {
    text-transform: uppercase;
    letter-spacing: .09em;
    font-size: .72rem;
    font-weight: 600;
    color: var(--seal);
    margin: 0;
}

.lede { font-size: 1.06rem; line-height: 1.6; color: var(--ink-soft); margin: 0 0 1.5rem; }

.hero-actions { display: flex; gap: .75rem; flex-wrap: wrap; }

.proof-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .7rem; }

.proof-list li {
    padding-left: 1.4rem;
    position: relative;
    color: var(--ink-soft);
    line-height: 1.45;
}

.proof-list li::before {
    content: "";
    position: absolute;
    left: 0;
    top: .5em;
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    background: var(--seal);
}

.proof-list span { color: var(--ink); font-weight: 600; }

.how .step {
    font-family: var(--serif);
    font-size: 1.6rem;
    color: var(--seal);
    line-height: 1;
    margin-bottom: .4rem;
}

.notice-quiet { background: var(--paper-sunken); border-color: var(--line-strong); }

/* =============================================================================
   Dashboard and tables
   ============================================================================= */

.grid-wide { display: grid; grid-template-columns: 1.4fr .6fr; gap: 1.25rem; align-items: start; }

.page-head-actions {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 1.5rem;
    flex-wrap: wrap;
}

.head-actions { display: flex; gap: .6rem; align-items: center; }

.card-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: .9rem;
}

.card-head h2 { margin: 0; }

.card-quiet { background: var(--paper-sunken); }

.filters { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }

.input-small { padding: .35rem .55rem; font-size: .85rem; width: auto; min-width: 8rem; }

.empty { color: var(--ink-faint); padding: 1.25rem 0; margin: 0; }

.row-main { display: block; font-weight: 600; }

.row-sub { display: block; color: var(--ink-faint); font-size: .8rem; }

.nowrap { white-space: nowrap; }

.due-soon { color: var(--bad); font-weight: 600; }

.tight { margin: .5rem 0 0; padding-left: 1.1rem; color: var(--ink-soft); }

.tight li { margin-bottom: .3rem; }

.progress {
    display: block;
    height: 4px;
    margin-top: .35rem;
    background: var(--paper-sunken);
    border-radius: 2px;
    overflow: hidden;
    min-width: 3.5rem;
}

.progress-fill { display: block; height: 100%; background: var(--ok); }

.actions { display: flex; gap: .75rem; align-items: center; margin-top: 1.25rem; }

.btn-danger { color: var(--bad); }

.btn-danger:hover { color: var(--bad); text-decoration: underline; }

.checklist { margin: .5rem 0 0; padding-left: 1.2rem; color: var(--ink-soft); }

.checklist li { margin-bottom: .35rem; }

.ready { color: var(--ok); font-weight: 600; margin: 0 0 .5rem; }

/* =============================================================================
   Request detail: documents, signers, evidence record
   ============================================================================= */

.doc-list, .signer-list { list-style: none; margin: 0 0 1rem; padding: 0; }

.doc-list li, .signer-list li {
    display: flex;
    gap: .9rem;
    align-items: flex-start;
    padding: .8rem 0;
    border-bottom: 1px solid var(--line);
}

.doc-main, .signer-main { flex: 1; min-width: 0; }

.doc-name, .signer-name { display: block; font-weight: 600; }

.doc-actions, .signer-actions {
    display: flex;
    gap: .6rem;
    align-items: center;
    flex-wrap: wrap;
    flex-shrink: 0;
}

/* A fingerprint is the evidence. It is shown whole, wraps where it must and selects in one
   gesture: cut short with an ellipsis, the one thing somebody might compare was uncomparable. */
.hash {
    font-size: .82rem;
    white-space: normal;
    word-break: break-all;
    max-width: none;
    user-select: all;
    color: var(--ink-faint);
}

.avatar {
    flex-shrink: 0;
    width: 2.1rem;
    height: 2.1rem;
    border-radius: 50%;
    background: var(--seal-tint);
    color: var(--seal);
    display: grid;
    place-items: center;
    font-size: .78rem;
    font-weight: 700;
}

.upload, .add-signer { border-top: 1px solid var(--line); padding-top: 1rem; }

.journal { list-style: none; margin: 0; padding: 0; }

.journal li {
    display: flex;
    gap: .9rem;
    padding: .5rem 0;
    border-bottom: 1px solid var(--line);
    font-size: .85rem;
}

.journal-when {
    flex-shrink: 0;
    font-family: var(--mono);
    font-size: .8rem;
    color: var(--ink-faint);
    padding-top: .1rem;
}

.journal-what { min-width: 0; }

/* =============================================================================
   Field editor
   -----------------------------------------------------------------------------
   The page is drawn by PDF.js into a canvas; the frames are absolutely placed
   over it in PERCENT, which is also how they are stored and how the server
   stamps them. Anything expressed in pixels here would break that agreement.
   ============================================================================= */

/* The document on the left, the panel on the right. Reading order for a page in a
   left-to-right language: the thing being worked on first, the tools beside it. The
   wide toggle folds the panel away entirely when the paper needs the whole width. */
.editor { display: grid; grid-template-columns: 1fr 24rem; gap: 1.25rem; align-items: start; }

.editor.is-wide { grid-template-columns: 1fr; }
.editor.is-wide .editor-side { display: none; }

.editor-side { display: flex; flex-direction: column; gap: 1rem; }

.editor-page {
    background: var(--paper-sunken);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 1rem;
    overflow: auto;
}

/* Everything from here to the handle sits on the white sheet and uses the --paper-* tokens,
   never the theme's. */
.page-container {
    position: relative;
    width: 100%;
    background: var(--paper-white);
    box-shadow: var(--shadow);
    cursor: crosshair;
}

.page-canvas { display: block; width: 100%; height: auto; }

.field-frame {
    position: absolute;
    border: 2px solid var(--paper-seal);
    background: color-mix(in srgb, var(--paper-seal) 12%, transparent);
    border-radius: 3px;
    cursor: move;
    user-select: none;
    overflow: hidden;
    min-width: 12px;
    min-height: 10px;
}

/* Selection is a ring, not an outline: the outline is what focus looks like everywhere else,
   and a box that is merely selected must not claim to have the keyboard. */
.field-frame.is-selected { box-shadow: 0 0 0 1px var(--paper-white), 0 0 0 3px var(--paper-ink); }

.field-frame.is-dragging { opacity: .75; }

.frame-initials { border-style: dashed; }
.frame-date     { border-color: var(--paper-ok);   background: color-mix(in srgb, var(--paper-ok) 12%, transparent); }
.frame-text     { border-color: var(--paper-warn); background: color-mix(in srgb, var(--paper-warn) 12%, transparent); }
.frame-checkbox { border-color: var(--paper-ink);  background: color-mix(in srgb, var(--paper-ink) 10%, transparent); }

.field-label {
    position: absolute;
    top: 0;
    left: 0;
    font-size: .6rem;
    line-height: 1.1;
    padding: 1px 3px;
    background: var(--paper-seal);
    color: var(--paper-white);
    white-space: nowrap;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    pointer-events: none;
}

.frame-date .field-label     { background: var(--paper-ok); }
.frame-text .field-label     { background: var(--paper-warn); }
.frame-checkbox .field-label { background: var(--paper-ink); }

.field-value {
    position: absolute;
    inset: auto 2px 2px 2px;
    font-size: .68rem;
    color: var(--paper-ink);
    pointer-events: none;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.field-handle {
    position: absolute;
    right: -4px;
    bottom: -4px;
    width: 11px;
    height: 11px;
    background: var(--paper-white);
    border: 2px solid var(--paper-seal);
    border-radius: 2px;
    cursor: nwse-resize;
}

.field-list { list-style: none; margin: 0; padding: 0; }

.field-list li {
    padding: .55rem .65rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    margin-bottom: .45rem;
    cursor: pointer;
}

.field-list li:hover { border-color: var(--line-strong); background: var(--paper-sunken); }

.field-list li.is-selected { border-color: var(--seal); background: var(--seal-tint); }

/* One row, one line: a dot in the signer's colour, what the box is, who it belongs to,
   and the two actions. No coordinates - the box is visible on the page beside it. */
.field-row { display: flex; align-items: center; gap: .55rem; }

.field-row-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }

.field-kind { font-weight: 600; }

.field-who {
    color: var(--ink-soft);
    font-size: .8rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.field-row-actions { display: flex; gap: .25rem; align-items: center; flex: none; }

/* A square, quiet, borderless button that carries one glyph. Used wherever a word would
   be longer than the thing it names: change, remove, previous page, whole width. */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--ink-soft);
    cursor: pointer;
    transition: background .12s ease, color .12s ease, border-color .12s ease;
}

.icon-btn svg { width: 1.05rem; height: 1.05rem; }

.icon-btn:hover:not(:disabled) {
    background: var(--paper-raised);
    border-color: var(--line);
    color: var(--ink);
}

.icon-btn:disabled { opacity: .3; cursor: default; }

.icon-btn-danger:hover:not(:disabled) { color: var(--bad); border-color: var(--bad); }

.pager { display: flex; gap: .35rem; align-items: center; }

.pager-centre { justify-content: center; padding: .35rem 0; }

.pager-input { display: inline-flex; align-items: center; gap: .4rem; margin: 0 .35rem; }

/* Typed, not clicked twenty-nine times. The spinner arrows go: they are two pixels wide
   and nobody hits them. */
.input-page {
    width: 3.4rem;
    text-align: center;
    padding: .3rem .35rem;
    font-variant-numeric: tabular-nums;
    -moz-appearance: textfield;
}

.input-page::-webkit-outer-spin-button,
.input-page::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.pager-of { color: var(--ink-soft); font-size: .85rem; white-space: nowrap; }

.pager-extra { margin-left: .6rem; padding-left: .6rem; border-left: 1px solid var(--line); }

/* The pages that already carry a field. Four numbers beat thirty Next presses. */
.page-chips { display: flex; flex-wrap: wrap; gap: .35rem; }

.page-chip {
    min-width: 2rem;
    padding: .3rem .45rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--paper-raised);
    color: var(--ink);
    font-size: .82rem;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
}

.page-chip:hover { border-color: var(--line-strong); }

.page-chip.is-on {
    background: var(--seal);
    border-color: var(--seal);
    color: var(--on-seal);
    font-weight: 600;
}

@media (max-width: 1000px) {
    .hero, .grid-wide, .editor { grid-template-columns: 1fr; }
    .editor-side { order: 2; }
}

/* =============================================================================
   Public signing page
   -----------------------------------------------------------------------------
   The screen a customer of our customer sees, usually once, often on a phone,
   and always at the moment they are about to commit to something. It gets no
   navigation and no distraction: one thing to do, and a clear account of what
   is being recorded about them.
   ============================================================================= */

.shell-sign { min-height: 100vh; display: flex; flex-direction: column; }

.topbar-sign { justify-content: space-between; }

.sign-badge {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    font-weight: 600;
    color: var(--ok);
    background: var(--ok-tint);
    border-radius: 999px;
    padding: .25rem .7rem;
}

.sign-body {
    flex: 1;
    width: 100%;
    max-width: 1180px;
    margin: 0 auto;
    padding: 2rem 1.25rem 3rem;
}

.sign-card { max-width: 34rem; margin: 2rem auto; }

.sign-card h1 {
    font-family: var(--serif);
    font-size: 1.7rem;
    line-height: 1.2;
    margin: .2rem 0 1rem;
}

/* One column. The document is the page, not a preview beside a form: what has to be
   signed is on the paper, and the paper is as wide as the screen allows. */
.sign-work { display: flex; flex-direction: column; gap: 1rem; }

.sign-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.15rem 1.25rem;
    background: var(--paper-raised);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

.sign-head h1 {
    font-family: var(--serif);
    font-size: 1.45rem;
    line-height: 1.2;
    margin: .1rem 0 0;
}

.sign-facts { display: flex; flex-wrap: wrap; gap: 1.5rem; margin: 0; }

.sign-facts dt {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ink-faint);
    font-weight: 600;
}

.sign-facts dd { margin: .2rem 0 0; font-size: .9rem; display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }

.sign-facts .who { display: flex; align-items: center; gap: .5rem; }

.sign-consent { display: flex; flex-direction: column; gap: .6rem; align-items: flex-start; }

/* The actions, repeated above and below the document. Whoever has just read to the bottom
   of page thirty should not have to scroll back up to sign. */
.sign-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: .8rem 1rem;
    background: var(--paper-raised);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    position: sticky;
    top: .5rem;
    z-index: 5;
}

.sign-bar-state { display: flex; align-items: center; gap: .9rem; flex-wrap: wrap; }

.sign-bar-actions { display: flex; align-items: center; gap: 1rem; }

/* One tab per document, with what is still owed on each. */
.doc-tabs { display: flex; flex-wrap: wrap; gap: .4rem; }

.doc-tab {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .4rem .8rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper-raised);
    color: var(--ink-soft);
    font: inherit;
    font-size: .85rem;
    cursor: pointer;
}

.doc-tab.is-on { border-color: var(--seal); color: var(--seal); background: var(--seal-tint); font-weight: 600; }

.doc-tab-left {
    min-width: 1.2rem;
    padding: 0 .3rem;
    border-radius: 999px;
    background: var(--warn);
    color: var(--on-warn);
    font-size: .72rem;
    font-weight: 700;
    text-align: center;
}

/* The paper. White whatever the theme: a contract is white, and a dark page would be
   the one place where the theme changes what somebody thinks they are signing. */
.page-paper {
    position: relative;
    width: 100%;
    background: var(--paper-white);
    border: 1px solid var(--line-strong);
    border-radius: 2px;
    box-shadow: var(--shadow);
    overflow: hidden;
}

.page-mark {
    position: absolute;
    right: .5rem;
    bottom: .4rem;
    font-size: .7rem;
    color: var(--paper-faint);
    background: color-mix(in srgb, var(--paper-white) 85%, transparent);
    border-radius: 4px;
    padding: 0 .3rem;
    pointer-events: none;
}

/* A place to sign, on the paper. Dashed and in the seal colour while it is empty, solid
   and green once there is something in it: filled and unfilled have to be tellable apart
   from across the room, because that is how somebody checks they are finished. */
.place {
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 2px dashed var(--paper-seal);
    border-radius: 4px;
    background: color-mix(in srgb, var(--paper-seal) 10%, transparent);
    cursor: pointer;
    overflow: hidden;
    transition: background .15s ease, box-shadow .15s ease;
}

/* The hover tint stops at 12%: the label inside is seal on a seal tint and falls under 4.5:1
   past that, so the ring carries the hover instead of the fill. */
.place:hover:not(:disabled):not(.is-inert) {
    background: color-mix(in srgb, var(--paper-seal) 12%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--paper-seal) 35%, transparent);
}

.place.is-filled { border-style: solid; border-color: var(--paper-ok); background: color-mix(in srgb, var(--paper-ok) 7%, transparent); }

.place.is-filled img { width: 100%; height: 100%; object-fit: contain; }

.place.is-optional { border-style: dotted; }

/* Before consent the places are visible but inert: seeing where you will have to sign is
   part of deciding to sign at all. */
.place.is-locked { cursor: not-allowed; border-color: var(--paper-line); background: color-mix(in srgb, var(--paper-faint) 4%, transparent); }
.place.is-locked:hover { box-shadow: none; }
.place.is-locked .place-text { color: var(--paper-faint); }

.place.is-inert { cursor: default; }
.place.is-other { border-style: dotted; opacity: .6; }

.place-text {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    padding: 0 .25rem;
    font-size: .68rem;
    font-weight: 700;
    color: var(--paper-seal);
    white-space: nowrap;
}

.place-text svg { width: .8rem; height: .8rem; }

.place-text-quiet { font-weight: 500; color: var(--paper-faint); }

.place-note { font-style: italic; font-weight: 400; color: var(--paper-faint); font-size: .62rem; }

.place-value { font-size: .72rem; font-weight: 600; color: var(--paper-ink); }

.place-mention {
    width: 100%;
    height: 100%;
    padding: .25rem .35rem;
    font-size: .68rem;
    line-height: 1.35;
    color: var(--paper-ink);
    text-align: left;
    overflow: hidden;
}

/* Written straight into the rectangle it will be printed in. */
.place-input {
    width: 100%;
    height: 100%;
    border: none;
    background: transparent;
    resize: none;
    padding: .25rem .35rem;
    font: inherit;
    font-size: .7rem;
    line-height: 1.35;
    color: var(--paper-ink);
}

.place-input:focus { outline: 2px solid var(--paper-seal); outline-offset: -2px; }

/* The access code, one box per character. A code read off a second message and typed into
   a phone gets mistyped; the boxes say how many are expected and where you are. */
.code-boxes { display: flex; gap: .5rem; justify-content: center; margin: .35rem 0 1rem; }

.code-box {
    width: 3rem;
    height: 3.4rem;
    text-align: center;
    font-family: var(--mono);
    font-size: 1.5rem;
    text-transform: uppercase;
    color: var(--ink);
    background: var(--paper-raised);
    border: 1px solid var(--line-control);
    border-radius: var(--radius-sm);
}

.code-box:focus { border-color: var(--seal); }
.code-box:focus-visible { outline: 2px solid var(--seal); outline-offset: 2px; box-shadow: none; }

.sign-gate { text-align: center; }
.sign-gate .eyebrow, .sign-gate p { text-align: center; }
/* The pad. A plain white box, because that is what a signature block looks like on
   paper and nobody needs teaching. */
.pad {
    display: block;
    width: 100%;
    height: 160px;
    background: var(--paper-white);
    border: 1px solid var(--line-control);
    border-radius: var(--radius-sm);
    touch-action: none;
    cursor: crosshair;
}

.tabs { display: flex; gap: .4rem; margin-bottom: .75rem; }

.tab {
    flex: 1;
    padding: .45rem .6rem;
    border: 1px solid var(--line);
    background: var(--paper-sunken);
    color: var(--ink-soft);
    border-radius: var(--radius-sm);
    cursor: pointer;
    font: inherit;
    font-size: .85rem;
}

.tab.is-on {
    background: var(--paper-raised);
    border-color: var(--seal);
    color: var(--ink);
    font-weight: 600;
}

.required {
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--bad);
    margin-left: .4rem;
}

textarea.input { resize: vertical; font: inherit; }

/* =============================================================================
   Invitations handed to the sender
   -----------------------------------------------------------------------------
   Shown once, in the response to the send. The codes exist nowhere else, so the
   page says so loudly rather than looking like something that can be reopened.
   ============================================================================= */

.card-invitations { border-left: 3px solid var(--seal); }

.link-cell {
    font-size: .82rem;
    word-break: break-all;
    max-width: 26rem;
    color: var(--ink-soft);
}

.code-chip {
    display: inline-block;
    font-family: var(--mono);
    font-size: 1.05rem;
    letter-spacing: .18em;
    font-weight: 700;
    background: var(--seal-tint);
    color: var(--seal);
    border-radius: var(--radius-sm);
    padding: .25rem .6rem;
}

/* =============================================================================
   State language: one tone vocabulary, five meanings
   -----------------------------------------------------------------------------
   The people using this are not computer people. They should not have to learn
   what "Sent" versus "Opened" means, and they should never have to read a status
   twice. So a state is a coloured dot plus a sentence in plain words, and the
   colour always means the same thing:

     ok    done, nothing to do          info  moving, nothing for you to do
     warn  needs you, or a date coming  bad   stopped
     mute  not started, or filed away

   One set of tone classes drives both the dot-and-sentence form and the chip
   form, so a state can never be green in one place and amber in another.
   ============================================================================= */

.tone-ok   { --tone: var(--ok);        --tone-tint: var(--ok-tint); }
.tone-info { --tone: var(--info);      --tone-tint: var(--info-tint); }
.tone-warn { --tone: var(--warn);      --tone-tint: var(--warn-tint); }
.tone-bad  { --tone: var(--bad);       --tone-tint: var(--bad-tint); }
.tone-mute { --tone: var(--ink-soft);  --tone-tint: var(--paper-sunken); }

.state {
    display: inline-flex;
    align-items: baseline;
    gap: .45rem;
    font-weight: 600;
    color: var(--tone, var(--ink));
    line-height: 1.35;
}

.state-dot {
    flex: 0 0 auto;
    align-self: center;
    width: .55rem;
    height: .55rem;
    border-radius: 50%;
    background: var(--tone, var(--ink-faint));
}

/* The line under a state: what it means for the reader, in normal words. */
.state-note { display: block; color: var(--ink-soft); font-weight: 400; font-size: .82rem; }

.notice-info { border-left-color: var(--info); background: var(--info-tint); color: var(--info); }

/* A chip that follows the tone vocabulary. The older badge-ok / -warn / -bad /
   -mute classes still work; this is what new markup uses. */
.badge.tone-ok, .badge.tone-info, .badge.tone-warn, .badge.tone-bad, .badge.tone-mute {
    background: var(--tone-tint);
    color: var(--tone);
    border-color: color-mix(in srgb, var(--tone) 25%, transparent);
}

/* =============================================================================
   Theme switch
   -----------------------------------------------------------------------------
   Three choices, not two: light, dark, and follow the machine. A toggle with
   only two states cannot express "whatever my laptop is doing", which is what
   most people actually want.
   ============================================================================= */

.theme-switch {
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    background: var(--paper-sunken);
    border: 1px solid var(--line);
    border-radius: 999px;
}

.theme-switch button {
    display: inline-grid;
    place-items: center;
    width: 30px;
    height: 26px;
    padding: 0;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--ink-faint);
    cursor: pointer;
    font: inherit;
    line-height: 0;
}

.theme-switch button:hover { color: var(--ink); background: var(--paper-raised); }

.theme-switch button[aria-pressed="true"] {
    background: var(--paper-raised);
    color: var(--seal);
    box-shadow: inset 0 0 0 1px var(--seal), var(--shadow);
}

.theme-switch svg { width: 15px; height: 15px; }

/* Visible to a screen reader, not to the eye. The icons alone would leave somebody
   using one guessing which button is which. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* =============================================================================
   Fewer things on screen
   ============================================================================= */

/* Technical facts a normal user never needs and an auditor always does: closed
   by default, one click away, never in anybody's face. */
.tech {
    margin-top: 1rem;
    border-top: 1px solid var(--line);
    padding-top: .75rem;
}

.tech summary {
    cursor: pointer;
    color: var(--ink-faint);
    font-size: .82rem;
    list-style: none;
}

.tech summary::-webkit-details-marker { display: none; }

.tech summary::before {
    content: "+";
    display: inline-block;
    width: 1rem;
    color: var(--ink-faint);
    font-family: var(--mono);
}

.tech[open] summary::before { content: "\2212"; }

.tech summary:hover { color: var(--ink); }

.tech-body { margin-top: .75rem; }

/* The dashboard table, calmer: four things per row instead of eight, the name
   doing the work, and the state carrying the colour. */
.table-calm td { padding: .85rem .75rem; vertical-align: top; }

.table-calm .cell-name { min-width: 15rem; }

.table-calm .cell-name a {
    font-weight: 600;
    font-size: 1rem;
    color: var(--ink);
}

.table-calm .cell-name a:hover { color: var(--seal); }

.table-calm tbody tr:hover { background: var(--paper-sunken); }

.table-calm .cell-when { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* One clear action per row, only when there is something to do. */
.row-action { white-space: nowrap; text-align: right; }

/* Big, readable count for the signature progress: "1 of 3" reads faster than a
   bar, and the bar under it is the glance. */
.count { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }

@media (max-width: 760px) {
    /* On a phone the table becomes a list of cards: a horizontally scrolling
       table is how a non-technical user loses the column that mattered. */
    .table-calm thead { display: none; }

    .table-calm, .table-calm tbody, .table-calm tr, .table-calm td { display: block; width: 100%; }

    .table-calm tr {
        border: 1px solid var(--line);
        border-radius: var(--radius);
        background: var(--paper-raised);
        padding: .9rem 1rem;
        margin-bottom: .75rem;
    }

    .table-calm td { border: none; padding: .2rem 0; }

    .row-action { text-align: left; padding-top: .6rem; }
}

/* =============================================================================
   The guided path
   -----------------------------------------------------------------------------
   Five steps across the top. A step is ticked when its work is done, not when
   it has been visited: ticking a step somebody walked past would be the most
   useless kind of encouragement.
   ============================================================================= */

.stepper {
    display: flex;
    flex-wrap: wrap;
    gap: .6rem 2.25rem;
    align-items: center;
    padding: 1.15rem 1.4rem;
    margin-bottom: 1.5rem;
    background: var(--paper-raised);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

.step { display: flex; align-items: center; gap: .7rem; }

/* The line between steps. Drawn on the step rather than between them, so a row
   that wraps on a narrow screen does not leave a dash pointing at nothing. */
.step + .step::before {
    content: "";
    width: 1.75rem;
    height: 1px;
    background: var(--ink-hush);
    margin-left: -1.4rem;
    margin-right: .6rem;
}

.step-mark {
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    flex: 0 0 auto;
    border-radius: 50%;
    border: 1.5px solid var(--line-strong);
    color: var(--ink-faint);
    font-size: .82rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.step-mark svg { width: 14px; height: 14px; }

.step-label { color: var(--ink-faint); font-size: .92rem; }

a.step-label:hover { color: var(--ink); }

.step.is-current .step-mark {
    border-color: var(--seal);
    background: var(--seal);
    color: var(--on-seal);
}

.step.is-current .step-label { color: var(--ink); font-weight: 600; }

.step.is-done .step-mark { border-color: var(--ok); color: var(--ok); background: var(--ok-tint); }
.step.is-done .step-label { color: var(--ink-soft); }

/* Back and next, at the foot of every step. */
.step-nav {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin-top: 1.25rem;
    flex-wrap: wrap;
}

.step-nav-gap { flex: 1 1 auto; }

.step-nav-why { color: var(--ink-faint); font-size: .88rem; }

.step-nav .btn[disabled] { opacity: .45; cursor: not-allowed; }

/* The small numbered list inside the field editor: how to place a box, in order. */
.mini-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .65rem; }

.mini-steps li { display: flex; gap: .65rem; align-items: flex-start; opacity: .55; }

.mini-steps li.is-current, .mini-steps li.is-done { opacity: 1; }

.mini-mark {
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    flex: 0 0 auto;
    border-radius: 50%;
    border: 1.5px solid var(--line-strong);
    color: var(--ink-faint);
    font-size: .75rem;
    font-weight: 600;
}

.mini-steps li.is-current .mini-mark { border-color: var(--seal); background: var(--seal); color: var(--on-seal); }
.mini-steps li.is-done .mini-mark { border-color: var(--ok); background: var(--ok-tint); color: var(--ok); }

/* =============================================================================
   Who is who
   -----------------------------------------------------------------------------
   A colour per signer, carried from the signers step to the boxes on the page.
   "Which of these is Marie's" is a question a colour answers without reading.
   ============================================================================= */

.legend { display: flex; flex-wrap: wrap; gap: .5rem 1.1rem; margin-bottom: 1rem; }

.legend-item { display: inline-flex; align-items: center; gap: .45rem; font-size: .88rem; }

.legend-dot {
    display: inline-block;
    width: .6rem;
    height: .6rem;
    border-radius: 50%;
    flex: 0 0 auto;
}

/* =============================================================================
   Popup
   -----------------------------------------------------------------------------
   Settings for one box, opened from the box itself, the way ColibaseApp does it.
   Better than a row in a side list: nobody has to match a line of text to a
   rectangle on a page.
   ============================================================================= */

.modal-veil {
    position: fixed;
    inset: 0;
    background: rgba(24, 26, 27, .45);
    display: grid;
    place-items: center;
    padding: 1.25rem;
    z-index: 50;
}

.modal {
    width: min(26rem, 100%);
    max-height: 85vh;
    display: flex;
    flex-direction: column;
    background: var(--paper-raised);
    border: 1px solid var(--line-control);
    border-radius: var(--radius);
    box-shadow: 0 12px 48px rgba(0, 0, 0, .28);
}

.modal-head {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .9rem 1.1rem;
    border-bottom: 1px solid var(--line);
}

.modal-head h2 { margin: 0; flex: 1 1 auto; font-size: 1.05rem; }

.modal-close {
    border: none;
    background: transparent;
    color: var(--ink-faint);
    cursor: pointer;
    padding: .2rem;
    line-height: 0;
    border-radius: var(--radius-sm);
}

.modal-close:hover { color: var(--ink); background: var(--paper-sunken); }
.modal-close svg { width: 17px; height: 17px; }

.modal-body { padding: 1.1rem; overflow-y: auto; }
.modal-body .field:last-of-type { margin-bottom: .5rem; }

.modal-foot {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .85rem 1.1rem;
    border-top: 1px solid var(--line);
    background: var(--paper-sunken);
    border-radius: 0 0 var(--radius) var(--radius);
}

/* The handle that opens it, in the corner of the box. Kept off the drag path in
   JavaScript: a press here must not also start moving the box. */
.field-cog {
    position: absolute;
    top: 1px;
    right: 1px;
    width: 18px;
    height: 18px;
    display: grid;
    place-items: center;
    padding: 0;
    border: none;
    border-radius: var(--radius-sm);
    background: color-mix(in srgb, var(--paper-white) 82%, transparent);
    color: var(--paper-ink);
    cursor: pointer;
    line-height: 0;
}

.field-cog:hover { background: var(--paper-white); }
.field-cog svg { width: 12px; height: 12px; }

@media (max-width: 760px) {
    .stepper { gap: .5rem 1rem; }
    .step + .step::before { display: none; }
    .step-label { font-size: .86rem; }
}

/* =============================================================================
   Spacing: one rhythm for the whole application
   -----------------------------------------------------------------------------
   Cards were sitting flush against each other and text was crowding the edges,
   because every block set its own margin - or forgot to. A single flow rule on
   the page container spaces whatever a page happens to put in it, so a screen
   built tomorrow is spaced without anybody thinking about it.
   ============================================================================= */

:root {
    --space-1: .5rem;
    --space-2: .85rem;
    --space-3: 1.25rem;
    --space-4: 1.75rem;
    --space-5: 2.5rem;
}

/* The flow rule. Anything that follows anything else in the page body gets air. */
.content > * + *,
.public-body > * + *,
.sign-body > * + * { margin-top: var(--space-3); }

/* Grids of cards space themselves the same way, so a row of cards and a single
   card below it are the same distance apart. */
.grid { gap: var(--space-3); }

.content > .grid,
.sign-body > .grid { margin-bottom: 0; }

/* A card had 1.15rem of padding and its content pressed on the border. */
.card { padding: var(--space-3) var(--space-3); }

.card > *:last-child { margin-bottom: 0; }

.card + .card { margin-top: var(--space-3); }

.card h2, .card h3 { margin-bottom: var(--space-2); }

/* Cards inside a grid cell stretch to the row height, so two columns of unequal
   content still line up at the bottom instead of leaving a ragged edge. */
.grid > .card { align-self: stretch; }

/* ".card + .card" above gives every card that follows another a top margin - right for cards
   stacked in a column, wrong inside a grid, where it hit the second and third dashboard tile:
   they sat 1.25rem lower and 1.25rem shorter than the first. The grid gap does the spacing. */
.grid > .card + .card { margin-top: 0; }

.page-head { margin-bottom: var(--space-4); }

.page-head h1 { margin-bottom: .35rem; }

/* The quiet line under the stat tiles was touching them. */
.stat-line { color: var(--ink-faint); font-size: .85rem; margin: 0; }

/* Definition lists: the value column was hard against the label. */
.facts { gap: var(--space-1) var(--space-4); }

.facts dt { padding-top: 1px; }

/* Forms inside a card breathe, and the last field does not push the button. */
.field { margin-bottom: var(--space-3); }

.field:last-of-type { margin-bottom: var(--space-2); }

.field label { display: block; margin-bottom: .3rem; font-weight: 600; font-size: .9rem; }

.field .hint { margin: .35rem 0 0; }

.actions { gap: var(--space-1); margin-top: var(--space-3); }

.notice { padding: var(--space-2) var(--space-3); margin-bottom: var(--space-3); }

.notice > *:last-child { margin-bottom: 0; }

.step-nav { margin-top: var(--space-4); }

.stepper { margin-bottom: var(--space-5); }

/* Lists of documents and signers: rows had no room and the first row hugged the
   heading. */
.doc-list, .signer-list { margin-top: var(--space-1); }

.doc-list li, .signer-list li { padding: var(--space-2) 0; }

.doc-list li:first-child, .signer-list li:first-child { padding-top: 0; }

.upload, .add-signer { margin-top: var(--space-3); padding-top: var(--space-3); }

/* The evidence record was a wall of lines. */
.journal li { padding: var(--space-2) 0; }

/* =============================================================================
   File input, with a drop zone
   -----------------------------------------------------------------------------
   A native file input is a grey button that says nothing about what it wants.
   This is a labelled area you can also drop onto - the gesture most people try
   first - built on the real input so it keeps working without JavaScript and
   stays reachable from the keyboard.
   ============================================================================= */

.dropzone {
    position: relative;
    display: block;
    border: 1.5px dashed var(--line-control);
    border-radius: var(--radius);
    background: var(--paper-sunken);
    padding: var(--space-4) var(--space-3);
    text-align: center;
    cursor: pointer;
    transition: border-color .12s ease, background-color .12s ease;
}

.dropzone:hover { border-color: var(--seal); background: var(--seal-tint); }

/* The real input covers the area: the click and the drop both land on it, so no
   JavaScript is needed for either. */
.dropzone input[type="file"] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

.dropzone input[type="file"]:focus-visible + .dropzone-body {
    outline: 2px solid var(--seal);
    outline-offset: 6px;
    border-radius: var(--radius-sm);
}

.dropzone.is-over { border-color: var(--seal); background: var(--seal-tint); }

.dropzone-body { pointer-events: none; }

.dropzone-icon { color: var(--seal); margin-bottom: var(--space-1); }

.dropzone-icon svg { width: 28px; height: 28px; }

.dropzone-main { display: block; font-weight: 600; margin-bottom: .2rem; }

.dropzone-sub { display: block; color: var(--ink-faint); font-size: .85rem; }

/* What was chosen, listed under the zone. */
.dropzone-picked {
    margin: var(--space-2) 0 0;
    padding: 0;
    list-style: none;
    text-align: left;
}

.dropzone-picked li {
    display: flex;
    gap: .5rem;
    align-items: baseline;
    font-size: .88rem;
    padding: .2rem 0;
}

.dropzone-picked .name { font-weight: 600; }

.dropzone-picked .size { color: var(--ink-faint); font-size: .82rem; }

/* =============================================================================
   The signature composer
   -----------------------------------------------------------------------------
   Opened from a place on the paper. Drawn or typed, plus initials when the
   document asks for them, and what will be stamped is shown before anything
   leaves the browser: nobody should meet their own signature for the first time
   in the sealed file.
   ============================================================================= */

.modal-wide { width: min(40rem, 100%); }

.pad-block { display: flex; flex-direction: column; gap: .5rem; }

.pad-block-small {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px dashed var(--line);
}

.pad-label {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ink-faint);
    font-weight: 600;
}

.pad-small { max-width: 15rem; height: 100px; }

.pad-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; }

.typed-block { display: flex; flex-direction: column; gap: .75rem; }

/* Each face renders the name it would produce. Choosing a font from its own name is
   the only way somebody can tell whether they like it. */
.faces { display: flex; flex-wrap: wrap; gap: .5rem; }

.face {
    flex: 1 1 9rem;
    padding: .5rem .75rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--paper-raised);
    color: var(--ink);
    font-size: 1.25rem;
    cursor: pointer;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.face:hover { border-color: var(--line-strong); }

.face.is-on { border-color: var(--seal); background: var(--seal-tint); box-shadow: inset 0 0 0 1px var(--seal); }

.previews { display: flex; flex-wrap: wrap; gap: 1rem; }

.preview {
    display: flex;
    flex-direction: column;
    gap: .35rem;
    padding: .5rem .75rem;
    background: var(--paper-white);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
}

.preview img { max-height: 4.5rem; max-width: 14rem; object-fit: contain; }

@media (max-width: 700px) {
    .code-box { width: 2.4rem; height: 3rem; font-size: 1.25rem; }
    .sign-bar { position: static; }
}

/* The editor and the signing surface earn more room than a page of prose: the paper is
   the content, and a 1080px column spends half a wide screen on margin. The wide toggle
   goes further still, because at that point the panel is gone and only paper is left. */
.content:has(.editor) { max-width: 1460px; }
.content:has(.editor.is-wide) { max-width: 1180px; }

/* =============================================================================
   Following a request
   -----------------------------------------------------------------------------
   "Waiting" does not answer the question somebody opens the page with, which is
   whether the other side has even looked at it. Four steps and a date each do.
   ============================================================================= */

.track-global { display: flex; flex-direction: column; gap: 1rem; }

.track-bar { display: flex; align-items: center; gap: .8rem; }

.track-bar .progress { flex: 1; }

.track-list { list-style: none; margin: 1.25rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .75rem; }

.track {
    display: flex;
    gap: .8rem;
    padding: .85rem 1rem;
    background: var(--paper-sunken);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
}

.track.is-refused { border-color: var(--bad); }

.track-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .2rem; }

.track-head { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }

.track-reason {
    margin: .35rem 0 0;
    padding-left: .7rem;
    border-left: 2px solid var(--bad);
    color: var(--ink-soft);
    font-style: italic;
    font-size: .88rem;
}

/* The four steps, side by side on a wide screen and stacked on a narrow one. A step that has
   not happened keeps its place: a gap that closes up hides what is still owed. */
.track-steps {
    list-style: none;
    margin: .6rem 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: .5rem .9rem;
}

.track-steps li { display: flex; flex-direction: column; padding-left: 1rem; position: relative; }

.track-dot {
    position: absolute;
    left: 0;
    top: .35rem;
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    background: var(--ink-hush);
}

.track-steps li.is-done .track-dot { background: var(--ok); }

.track-what { font-size: .8rem; color: var(--ink-faint); }

.track-steps li.is-done .track-what { color: var(--ink-soft); }

.track-when { font-size: .85rem; color: var(--ink-soft); font-variant-numeric: tabular-nums; }

.track-steps li.is-done .track-when { color: var(--ink); font-weight: 600; }

@media (max-width: 620px) {
    .track { flex-direction: column; }
}

/* Picking a colleague: one select and one button on the same line. */
.pick-row { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
.pick-row .input { flex: 1 1 18rem; }

.add-colleague { margin-bottom: 1rem; }

/* A rule with a word in it: "or type somebody new" reads as a choice, two stacked forms do not. */
.or-line {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin: 1.25rem 0;
    color: var(--ink-faint);
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .06em;
}

.or-line::before,
.or-line::after { content: ""; flex: 1; height: 1px; background: var(--line); }


/* =============================================================================
   Row menus
   -----------------------------------------------------------------------------
   A <details> element with the actions inside. Buttons for everything is how a
   screen fills up with things nobody presses: the row keeps its information and
   the actions appear when asked for.
   ============================================================================= */

.menu { position: relative; flex: none; }

.menu-button {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .3rem .45rem;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--ink-soft);
    cursor: pointer;
    list-style: none;
    user-select: none;
}

/* Safari and Chrome both draw their own marker on a summary. */
.menu-button::-webkit-details-marker { display: none; }
.menu-button::marker { content: ""; }

.menu-button svg { width: 1.1rem; height: 1.1rem; }

.menu-button:hover { background: var(--paper-raised); border-color: var(--line); color: var(--ink); }

.menu[open] > .menu-button {
    background: var(--paper-raised);
    border-color: var(--line-strong);
    color: var(--ink);
}

.menu-label { font-size: .82rem; }

.menu-panel {
    position: absolute;
    right: 0;
    top: calc(100% + .3rem);
    z-index: 30;
    min-width: 14rem;
    padding: .35rem;
    display: flex;
    flex-direction: column;
    gap: .1rem;
    background: var(--paper-raised);
    border: 1px solid var(--line-control);
    border-radius: var(--radius);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .22);
}

.menu-panel.is-left { right: auto; left: 0; }

/* Every child is one row of the menu, whatever it is: a link, or a button in its own
   form. They have to be indistinguishable, or the menu reads as two lists. */
.menu-panel a,
.menu-panel button {
    display: flex;
    align-items: center;
    gap: .5rem;
    width: 100%;
    padding: .45rem .55rem;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--ink);
    font: inherit;
    font-size: .88rem;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

.menu-panel a:hover,
.menu-panel button:hover { background: var(--paper-sunken); }

.menu-panel button:disabled { color: var(--ink-faint); cursor: default; background: transparent; }

.menu-panel .is-danger { color: var(--bad); }
.menu-panel .is-danger:hover { background: var(--bad-tint); }

.menu-panel form { margin: 0; }

/* A line of explanation inside a menu, and the rule that separates a group. */
.menu-note {
    padding: .35rem .55rem .5rem;
    color: var(--ink-faint);
    font-size: .76rem;
    line-height: 1.4;
}

.menu-split { height: 1px; background: var(--line); margin: .25rem 0; }

/* Open plus its menu, on a table row. */
.row-actions { display: flex; align-items: center; gap: .25rem; justify-content: flex-end; }

/* A menu inside a table cell has to escape the cell, and a scrolling wrapper clips it. */
.table-scroll { overflow-x: auto; overflow-y: visible; }

.table-calm td.row-action { overflow: visible; }

/* The dots sit to the left of Open, in a column of their own: rows without a menu keep
   Open in the same place instead of sliding right. */
.row-actions .menu { order: -1; }
.row-actions { min-width: 6.5rem; }

/* A quiet link that takes the width of the card, for the one way out of the code page. */
.btn-link.btn-block {
    display: block;
    width: 100%;
    margin-top: .75rem;
    padding: .5rem;
    text-align: center;
    border: none;
    background: transparent;
    font: inherit;
    font-size: .88rem;
    cursor: pointer;
}

/* =============================================================================
   The grid, in this product's colours
   -----------------------------------------------------------------------------
   HelpGridV3 comes from CoreBlazor with Colibase's palette, and it holds every
   colour in --c-* tokens on .gdg precisely so a host can re-map them. That is all
   this block does: no rule of the ported CSS is rewritten, so the component can be
   copied back and forth without a merge.

   The doubled class is deliberate. The ported file is scoped CSS, so its own rule
   lands as .gdg[b-xxxxx] - two simple selectors - and it is served after app.css.
   [data-theme] .gdg.gdg is one weight heavier, so this wins whatever the order.
   ============================================================================= */

[data-theme] .gdg.gdg {
    --c-accent: var(--seal);
    --c-accent-700: var(--seal-hover);
    --c-accent-soft: var(--seal-tint);
    --c-accent-soft-2: var(--seal-tint);
    --c-border: var(--line);
    --c-border-2: var(--line-strong);
    --c-surface: var(--paper-raised);
    --c-surface-2: var(--paper-sunken);
    --c-surface-3: var(--line);
    --c-row-sel: var(--seal-tint);
    --c-ink: var(--ink);
    --c-ink-2: var(--ink-soft);
    --c-ink-3: var(--ink-faint);
    --c-navy: var(--ink);
    --c-on-navy: var(--paper);
    --c-info: var(--info);
    --c-info-soft: var(--info-tint);
    --c-warning-soft: var(--warn-tint);
    --sh-lg: var(--shadow);

    font-family: var(--sans);
    font-size: .92rem;
}

/* Dark. The grid paints a fixed #fff on --c-accent and --c-info (the current page number, the
   ticked checkbox, the compare tag) and offers no token to say otherwise, so in the dark theme
   those two keep their light-theme values: white passes on them (5.4 / 8.2:1) where it failed on
   the lighter dark seal (3.4:1). The price is accent-as-text - the Rules link, a danger item -
   at about 3:1 on a dark surface; the cure is a --c-on-accent token in CoreBlazor. The selection
   bar stays dark as well, because its own buttons are white on translucent white. */
[data-theme="dark"] .gdg.gdg {
    --c-accent: #a2543a;
    --c-accent-700: #8c452f;
    --c-info: #1f5566;
    --c-info-soft: #e6eef1;
    --c-navy: #2a2f33;
    --c-on-navy: var(--ink);
}

/* The card the grid draws is inside one of ours already: no second border, no second
   radius, no shadow on a shadow. */
[data-theme] .gdg.gdg .gdg-card {
    border: none;
    border-radius: 0;
    background: transparent;
}

/* Headings in this product's voice: small, spaced, quiet - the same as .table th. */
[data-theme] .gdg.gdg .gdg-th {
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ink-faint);
    font-weight: 600;
    background: transparent;
}

[data-theme] .gdg.gdg .gdg-cell { padding: .85rem .75rem; vertical-align: top; font-size: .92rem; font-variant-numeric: tabular-nums; }

[data-theme] .gdg.gdg .gdg-datarow:hover { background: var(--paper-sunken); }

/* A row whose file is about to be deleted, from RowClassFunc. */
[data-theme] .gdg.gdg .gdg-datarow.is-due-soon { box-shadow: inset 3px 0 0 var(--warn); }

/* The document name reads as the link it is, like every other listing on the site. */
.grid-name { font-weight: 600; color: var(--ink); text-decoration: none; display: block; }
.grid-name:hover { color: var(--seal); }

/* The toolbar buttons borrow our own quiet button rather than inventing a third look. */
[data-theme] .gdg.gdg .gdg-btn {
    border-radius: var(--radius-sm);
    border-color: var(--line);
    background: var(--paper-raised);
    color: var(--ink-soft);
}

[data-theme] .gdg.gdg .gdg-btn:hover { border-color: var(--line-strong); color: var(--ink); }

/* A row menu opens out of its cell, and the grid's card and scroller both clip. The trade
   is deliberate: five columns sized in rem fit any desktop width, so what is given up is a
   horizontal scrollbar that never appeared, and what is gained is a menu that is not cut in
   half. The grid's own column menus render at grid level and were never affected. */
[data-theme] .gdg.gdg .gdg-card,
[data-theme] .gdg.gdg .gdg-scroll { overflow: visible; }

/* The cell clips too, and that one was missed: every .gdg-cell carries
   `overflow: hidden; text-overflow: ellipsis`, which is exactly right for a long label and
   exactly wrong for a panel that hangs below the row - the menu showed as a sliver. Only the
   cells that actually hold a menu are freed, so the ellipsis survives everywhere else. */
[data-theme] .gdg.gdg .gdg-cell:has(.menu) { overflow: visible; }

/* Below 1000px the rem-sized columns stop fitting, and a table wider than the phone dragged the
   whole page sideways (485px on the dashboard, 665px on the team page, at 390px). The scroller
   scrolls again there. The row menu may get clipped on a phone; that is the lesser evil. */
@media (max-width: 1000px) {
    [data-theme] .gdg.gdg .gdg-scroll { overflow-x: auto; }
}

/* =============================================================================
   The 0.4 batch: renaming in place, batch sends, templates, attachments,
   observers, the archive toggle. Small pieces reusing the existing tokens.
   ============================================================================= */

/* A one-line form: label, a tight input, a button, on one row. */
.inline-form { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin: .75rem 0; }

/* The same class name also sits inside a grid cell (the role and plan selectors on a row), where
   the earlier definition - inline, no margin of its own - was the one meant. Restored there. */
.gdg-cell .inline-form { display: inline-flex; flex-wrap: nowrap; gap: .35rem; margin: 0; }
.input-tight { width: 5rem; }

/* Renaming a document where its name is shown. The input looks like text until touched. */
.doc-rename { display: flex; align-items: center; gap: .5rem; }
.input-bare {
    border-color: transparent;
    background: transparent;
    padding-left: .25rem;
    max-width: 22rem;
}
.input-bare:hover, .input-bare:focus { border-color: var(--line); background: var(--paper); }

/* The archive toggle sits right above the grid, aligned with its toolbar. */
.grid-side-toggle { margin-bottom: .5rem; justify-content: flex-end; }

/* Templates offered on the new-request screen. */
.template-list { list-style: none; margin: 0 0 1rem; padding: 0; display: grid; gap: .5rem; }
.template-list li form {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas: "name button" "sub button";
    align-items: center;
    gap: 0 .75rem;
    padding: .5rem .75rem;
    border: 1px solid var(--line);
    border-radius: .5rem;
}
.template-list .doc-name { grid-area: name; }
.template-list .row-sub { grid-area: sub; }
.template-list .btn { grid-area: button; }

/* A folded-away section: the batch send lives behind one. */
.fold { margin-top: 1rem; }
.fold summary { cursor: pointer; color: var(--ink-soft); }
.fold[open] summary { margin-bottom: .5rem; }
.fold textarea { margin-bottom: .75rem; }

/* What signers attached, on both sides of the circuit. */
.attach-list { list-style: none; margin: 0 0 .75rem; padding: 0; display: grid; gap: .35rem; }
.sign-attachments { margin-bottom: 1rem; }

/* The file picker styled as the button it acts like; the input itself is invisible. */
.attach-pick { position: relative; overflow: hidden; display: inline-block; }
.attach-pick input[type="file"] {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
}

/* The sealed copies on the closed signing page. */
.sign-downloads { display: grid; gap: .5rem; margin-top: 1rem; justify-items: start; }

/* A small form inside a row menu: the replace-signer one. */
.menu-form { display: grid; gap: .5rem; padding: .5rem .75rem .75rem; border-top: 1px solid var(--line); }

/* The sessions screen: one row per signed-in browser. */
.session-list { list-style: none; margin: 0 0 1rem; padding: 0; }
.session-list li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: .65rem 0;
    border-bottom: 1px solid var(--line);
}
.session-list li:last-child { border-bottom: none; }

/* The since-you-last-looked feed on the dashboard. */
.news-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .35rem; }
.news-list li { display: flex; gap: .75rem; align-items: baseline; }
.news-list .row-sub { flex: 0 0 auto; }

/* The operator's front-door tiles: whole card is the link, no underline noise. */
.tile-link { text-decoration: none; color: inherit; display: block; transition: border-color .12s; }
.tile-link:hover { border-color: var(--ink-faint, #8b9196); text-decoration: none; }

/* Folded admin sections: the summary line reads as a heading, cursor says it opens. */
.fold > summary { list-style-position: outside; }
.fold > summary h2 { cursor: pointer; }

/* The language picker in the top bar: compact, quiet, next to the theme switch. */
.lang-pick { display: flex; align-items: center; }
.lang-pick select { min-width: 6.5rem; }

/* =============================================================================
   Paper, for real
   -----------------------------------------------------------------------------
   The evidence page, the certificate and a request's record get printed and filed.
   On paper there is no dark theme, no navigation, no button and nothing that only
   works when pressed. The light palette is forced whatever the screen was showing.
   ============================================================================= */

@media print {
    :root, :root[data-theme="dark"] {
        color-scheme: light;
        --paper: #fff;
        --paper-raised: #fff;
        --paper-sunken: #fff;
        --ink: #000;
        --ink-soft: #222;
        --ink-faint: #444;
        --ink-hush: #666;
        --line: #999;
        --line-strong: #666;
        --line-control: #666;
        --seal: #000;
        --seal-hover: #000;
        --seal-tint: #fff;
        --shadow: none;
    }

    body { background: #fff; color: #000; }

    /* The chrome, the navigation, and anything that only does something when pressed. */
    .topbar, .theme-switch, .lang-pick, .public-foot, .menu, .sign-bar, .step-nav, .actions,
    .row-actions, #blazor-error-ui, .btn { display: none; }

    .content, .public-body, .sign-body { max-width: none; padding: 0; }

    .card, .sign-head, .stepper, .notice, .track {
        border: 1px solid #999;
        box-shadow: none;
        break-inside: avoid;
    }

    tr, .journal li, .doc-list li, .signer-list li { break-inside: avoid; }

    /* The fingerprint, whole: it is the one thing the printout exists to carry. */
    .hash { white-space: normal; word-break: break-all; max-width: none; font-size: 9pt; }

    /* A link on paper is its address or nothing. */
    a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 8pt; color: #444; word-break: break-all; }

    /* The technical facts open on paper: an auditor cannot click. The first rule carries the
       only !important on this sheet - it has to beat the closed state - and only reaches
       engines that lay the details' content out in the light tree. Chrome (131+) hides it
       with content-visibility on the ::details-content pseudo-element; the second rule is
       for that. */
    .tech > *:not(summary) { display: block !important; }
    .tech::details-content { content-visibility: visible; }
}

/* Somebody who asked their machine for less movement gets less movement: every transition and
   animation collapses to one frame. The !important is the point here - this has to beat every
   animation declared above, and the ones in the scoped grid and reconnect sheets served after
   this file. Duration .01ms rather than 0 so animationend still fires for scripts that wait on it. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        transition-duration: .01ms !important;
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
    }
}

/* Windows high contrast. The browser repaints everything in the system palette: a coloured dot
   with no border becomes an empty circle, a bar disappears, and a tab that is "on" only by its
   background looks like the others. The dots and the bar keep their colour; anything that is on
   gets the system highlight drawn around it. */
@media (forced-colors: active) {
    .state-dot, .legend-dot, .track-dot, .progress-fill { forced-color-adjust: none; }

    .tab.is-on, .doc-tab.is-on, .page-chip.is-on, .face.is-on,
    .theme-switch button[aria-pressed="true"] { outline: 2px solid Highlight; }
}

/* ------------------------------------------------------------------ accessibility hooks */
/* Skip link: hidden with .sr-only until focused, then pinned top-left over everything. Wins
   over .sr-only by specificity, so the markup keeps both classes. */
.skip-link:focus {
    position: fixed; top: .5rem; left: .5rem; width: auto; height: auto; overflow: visible;
    clip: auto; clip-path: none; white-space: normal; margin: 0; padding: .5rem .8rem;
    background: var(--paper-raised); color: var(--ink); border: 1px solid var(--line-control);
    border-radius: var(--radius-sm); z-index: 100; text-decoration: none;
}

/* Field list rows are buttons now (keyboard reachable); the li is a plain container. */
.field-list li { cursor: default; }
.field-row-pick {
    display: flex; align-items: center; gap: .55rem; flex: 1 1 auto; min-width: 0;
    padding: 0; border: 0; background: transparent; color: inherit; font: inherit;
    text-align: left; cursor: pointer;
}
.field-frame:focus-visible { outline: 2px solid var(--paper-seal); outline-offset: 2px; }

/* Native <dialog> reusing the .modal skin: author display:flex would keep a closed dialog
   visible, so closed ones are hidden explicitly; the backdrop replaces .modal-veil. */
dialog.modal { padding: 0; margin: auto; color: var(--ink); }
dialog.modal:not([open]) { display: none; }
dialog.modal::backdrop { background: rgba(24, 26, 27, .45); }

/* The Blazor error banner's dismiss is a real button now. */
#blazor-error-ui .dismiss { border: 0; background: transparent; color: inherit; font: inherit; padding: 0; }
.head-actions > div .hint { max-width: 18rem; }

/* Download buttons on the closed signer card. */
.sign-downloads { display: flex; flex-direction: column; gap: .6rem; margin-top: 1rem; }

/* One-time lists of secrets (recovery codes): chips that wrap, each selectable in one click. */
.code-chip-list { display: flex; flex-wrap: wrap; gap: .4rem .5rem; margin: .5rem 0; }
.code-chip.is-copyable { user-select: all; }

/* Usage bars carry a state when a quota is close or past: same three tones as everywhere else. */
.progress-fill.is-warn { background: var(--warn); }
.progress-fill.is-bad { background: var(--bad); }
