/*
  Duka administration portal.

  Deliberately not storefront.css, and not a variation on it. That stylesheet is a 420px phone frame
  for shoppers on a slow Android connection; this is two operators on laptops reading a table of
  everyone who can reach every merchant's data. Sharing it would have put a permissions matrix
  inside a phone.

  Kept from the house style, because it is right rather than because it is the house style:
  elevation is a 1px line on a white surface, never a shadow.

  Departed from, deliberately: the warm clay palette (this is not a shop and should never be
  mistaken for one), the 420px column, the 10-14px radii, the 44px phone touch targets, and
  Public Sans.

  One idea carries the design. The portal's subject is grants - who may do what - so every screen
  renders access as the same seven columns in the same order, split into the two bands the
  permission set actually has: two grants that let you SEE something, five that let you CHANGE
  something. Two accounts can then be compared by shape without reading a word, and the checkbox
  that edits a grant sits in the very cell that displays it, so switching to edit moves nothing.

  Contrast, measured rather than assumed (WCAG 2.1 relative luminance):
    ink #12232B on paper #FFFFFF ............ 16.15:1
    ink #12232B on ground #E7EAEC ........... 13.36:1
    ink-2 #4A5C64 on paper .................. 6.99:1
    ink-2 #4A5C64 on ground ................. 5.78:1
    signal #0B5E63 on paper ................. 7.51:1   (and paper on signal, for buttons)
    grant #175C3C on grant-bg #E4EFE9 ....... 6.81:1
    refuse #8A2B2B on refuse-bg #F6E7E7 ..... 7.11:1
    caution #7A5200 on caution-bg #F6EEDD ... 6.05:1
    field-line #6E7C82 on paper ............. 4.31:1   (>= 3:1, WCAG 1.4.11 non-text)
    focus ring signal on paper / ground ..... 7.51:1 / 6.22:1
    paper #FFFFFF on caution #7A5200 ........ 6.92:1   (the impersonation banner; see .acting)
*/

:root {
    color-scheme: light;

    --ground: #E7EAEC;
    --paper: #FFFFFF;

    --ink: #12232B;
    --ink-2: #4A5C64;

    --rule: #DDE3E6;
    --rule-2: #C7D0D4;
    --field-line: #6E7C82;

    --signal: #0B5E63;
    --signal-2: #083F43;

    --grant: #175C3C;
    --grant-bg: #E4EFE9;
    --refuse: #8A2B2B;
    --refuse-bg: #F6E7E7;
    --caution: #7A5200;
    --caution-bg: #F6EEDD;

    /* Near-square. An instrument, not an app. One value, everywhere. */
    --r: 3px;
}

* { box-sizing: border-box; }

[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    background: var(--ground);
    color: var(--ink);
    font-family: "IBM Plex Sans", "Segoe UI", system-ui, -apple-system, sans-serif;
    font-size: 15px;
    font-weight: 400;
    line-height: 1.55;
}

a { color: var(--signal); text-underline-offset: 3px; }

a:hover { color: var(--signal-2); }

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

/*
   One focus treatment for the whole portal, on :focus-visible so a mouse click does not paint it.
   Three pixels rather than two: these screens are read at arm's length on a laptop, and the ring is
   the only thing that says where the keyboard is.
*/
:focus-visible {
    outline: 3px solid var(--signal);
    outline-offset: 2px;
}

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

/* ---------- impersonation ---------- */

/*
   The one place in this portal that fills a whole band with a warning colour rather than tinting a
   box with it - .caution and .state--warn use --caution as restrained text on a pale ground, which
   reads as "worth noting". This has to read as "you are not looking at your own screen", so it is
   the solid colour, full width, ahead of even the top bar - the first thing painted and the first
   thing seen on every page of the request, chromed or not.
*/
.acting {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    padding: 0.65rem 1.75rem;
    background: var(--caution);
    color: var(--paper);
    font-weight: 500;
}

.acting__dot {
    flex: none;
    width: 0.55rem;
    height: 0.55rem;
    border-radius: 50%;
    background: var(--paper);
}

.acting__out {
    margin-left: auto;
    flex: none;
    color: var(--paper);
    font-weight: 600;
    white-space: nowrap;
}

.acting__out:hover { color: var(--ground); }

/* ---------- chrome ---------- */

.top {
    background: var(--paper);
    border-bottom: 1px solid var(--rule-2);
}

.top__in {
    display: flex;
    align-items: stretch;
    gap: 2rem;
    max-width: 78rem;
    margin: 0 auto;
    padding: 0 1.75rem;
}

.top__mark {
    display: flex;
    align-items: center;
    font-weight: 600;
    letter-spacing: -0.01em;
    white-space: nowrap;
}

.top__nav { display: flex; gap: 1.5rem; flex: 1; }

.top__nav a {
    display: flex;
    align-items: center;
    padding: 0.9rem 0 0.85rem;
    color: var(--ink-2);
    text-decoration: none;
    /* The active item is marked by a bar on the edge it shares with the content below it, not by a
       pill or a tinted block: the mark points at where you are, rather than decorating a link. */
    border-bottom: 3px solid transparent;
}

.top__nav a:hover { color: var(--ink); }

.top__nav a[aria-current="page"] {
    color: var(--ink);
    font-weight: 500;
    border-bottom-color: var(--signal);
}

.top__who {
    display: flex;
    align-items: center;
    gap: 1rem;
    color: var(--ink-2);
    white-space: nowrap;
}

.top__out {
    padding: 0;
    border: 0;
    background: none;
    color: var(--signal);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.top__out:hover { color: var(--signal-2); }

.main {
    max-width: 78rem;
    margin: 0 auto;
    padding: 2.25rem 1.75rem 5rem;
}

/* Sign in and enrolment: no chrome to return to, so one column, left-aligned inside it. */
.focus {
    max-width: 33rem;
    margin: 0 auto;
    padding: 4.5rem 1.75rem 5rem;
}

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

h1 {
    font-size: 1.625rem;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -0.02em;
    margin: 0;
}

h2 {
    font-size: 1.125rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    margin: 0 0 0.5rem;
}

.lede {
    max-width: 46ch;
    margin: 0.4rem 0 0;
    color: var(--ink-2);
}

.head { margin-bottom: 1.75rem; }

.lede + form, .lede + .steps, .lede + .codes { margin-top: 1.5rem; }

.meta { color: var(--ink-2); font-size: 0.8125rem; }

/*
   Monospace has exactly one job here and never any other: strings a person has to transcribe
   character by character - a base32 secret, a recovery code, a temporary password. IBM Plex Mono
   slashes its zero and keeps 1, l and I apart, which is the difference between a working
   authenticator and a support call.
*/
.mono {
    font-family: "IBM Plex Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;
    font-variant-ligatures: none;
}

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

.panel {
    background: var(--paper);
    border: 1px solid var(--rule-2);
    border-radius: var(--r);
    padding: 1.5rem;
}

.panel + .panel { margin-top: 1.25rem; }

/*
   The bar across the top of a focus panel is the page's only ornament, and it carries state: petrol
   while the form is waiting, red when the last attempt was refused.
*/
.panel--focus { border-top: 3px solid var(--signal); padding: 1.75rem; }

.panel--refused { border-top-color: var(--refuse); }

.panel__foot {
    margin: 1.5rem -1.75rem -1.75rem;
    padding: 1rem 1.75rem;
    border-top: 1px solid var(--rule);
    background: #F7F9FA;
    border-radius: 0 0 var(--r) var(--r);
    color: var(--ink-2);
    font-size: 0.8125rem;
}

/* ---------- messages ---------- */

.alarm, .notice, .caution {
    border: 1px solid;
    border-radius: var(--r);
    padding: 0.7rem 0.85rem;
    margin: 0 0 1.25rem;
}

.alarm { background: var(--refuse-bg); border-color: #E0BDBD; color: var(--refuse); }

.notice { background: var(--grant-bg); border-color: #BCD6C8; color: var(--grant); }

.caution { background: var(--caution-bg); border-color: #DFCFA6; color: var(--caution); }

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

.field { display: block; margin-bottom: 1.15rem; }

/* Label, control, hint - three siblings, so the hint never lands inside the label and becomes part
   of the control's accessible name. */
.field > label {
    display: block;
    margin-bottom: 0.3rem;
    font-weight: 500;
}

.field input[type="text"],
.field input[type="email"],
.field input[type="password"],
.field select {
    width: 100%;
    background: var(--paper);
    border: 1px solid var(--field-line);
    border-radius: var(--r);
    padding: 0.5rem 0.6rem;
    min-height: 2.5rem;
}

.field--code input, .field--otp input {
    letter-spacing: 0.28em;
    font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
}

/* Six digits, and the box says so. */
.field--code input { max-width: 9rem; }

/* Six digits or a ten-character recovery code, so it has to hold the longer one. */
.field--otp input { max-width: 15rem; }

/* The catalogue screen is the portal's first with a number and a paragraph on it. Same box as the
   text fields above, so a price does not read as a different kind of control from a name. */
.field input[type="number"],
.field textarea {
    width: 100%;
    background: var(--paper);
    border: 1px solid var(--field-line);
    border-radius: var(--r);
    padding: 0.5rem 0.6rem;
    min-height: 2.5rem;
}

.field textarea { min-height: 5.5rem; resize: vertical; }

/* A tick and its words on one line, and the words are the label: clicking either toggles it, which
   on a control that decides whether a shop's product is visible at all is worth the two rules. */
.check {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 1.15rem;
    font-weight: 500;
}

.check input[type="checkbox"] { width: 1.15rem; height: 1.15rem; }

/* Inside a sheet the option rows are already in a grid, so their inputs carry the box themselves. */
.sheet input[type="text"],
.sheet input[type="number"] {
    width: 100%;
    min-width: 6rem;
    background: var(--paper);
    border: 1px solid var(--field-line);
    border-radius: var(--r);
    padding: 0.4rem 0.5rem;
    min-height: 2.25rem;
}

.field input::placeholder { color: var(--ink-2); }

.hint { margin: 0.3rem 0 0; color: var(--ink-2); font-size: 0.8125rem; }

.btn {
    display: inline-block;
    background: var(--signal);
    color: var(--paper);
    border: 1px solid var(--signal);
    border-radius: var(--r);
    padding: 0.5rem 1rem;
    min-height: 2.5rem;
    font-weight: 500;
    cursor: pointer;
    transition: background-color 120ms ease;
}

.btn:hover { background: var(--signal-2); border-color: var(--signal-2); }

.btn--quiet {
    background: var(--paper);
    color: var(--signal);
    border-color: var(--field-line);
}

.btn--quiet:hover { background: #F1F4F5; color: var(--signal-2); }

.btn--small { padding: 0.3rem 0.65rem; min-height: 2rem; font-size: 0.8125rem; }

.btn[disabled] { opacity: 0.5; cursor: not-allowed; }

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

/* ---------- the grant sheet ---------- */

.sheetwrap { overflow-x: auto; }

.sheet {
    width: 100%;
    border-collapse: collapse;
    background: var(--paper);
    border: 1px solid var(--rule-2);
    border-radius: var(--r);
}

.sheet caption {
    caption-side: top;
    text-align: left;
    color: var(--ink-2);
    padding-bottom: 0.6rem;
}

.sheet th, .sheet td {
    padding: 0.6rem 0.75rem;
    text-align: left;
    vertical-align: middle;
    border-bottom: 1px solid var(--rule);
}

.sheet thead th {
    /* Sentence case, not tracked-out capitals. A column head is a word, not a badge. */
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--ink-2);
    vertical-align: bottom;
}

.sheet thead tr:last-child th { border-bottom: 1px solid var(--rule-2); }

.sheet tbody tr:last-child th,
.sheet tbody tr:last-child td { border-bottom: 0; }

.sheet tbody tr:hover td, .sheet tbody tr:hover th { background: #F7F9FA; }

/* The two bands. A single rule between them does the work a repeated legend would. */
.sheet thead th.band {
    text-align: center;
    font-weight: 600;
    color: var(--ink);
    padding-bottom: 0.15rem;
}

.sheet .band--see,
.sheet .band--change,
.sheet .col--first { border-left: 1px solid var(--rule-2); }

.sheet .grantcell { text-align: center; width: 5.5rem; }

.grantcell input[type="checkbox"] {
    width: 1.05rem;
    height: 1.05rem;
    margin: 0;
    accent-color: var(--signal);
    cursor: pointer;
}

.grantcell input[disabled] { cursor: not-allowed; }

/*
   Read-only marks, on the overview. Filled for held, an empty well for not held - so a row of
   grants reads as a shape before it reads as words. The word is still there for a screen reader.
*/
.mark {
    display: inline-block;
    width: 1.05rem;
    height: 1.05rem;
    border-radius: var(--r);
    border: 1px solid var(--field-line);
}

.mark--on { background: var(--grant); border-color: var(--grant); }

.who__name { display: block; font-weight: 500; }

.who__mail { display: block; color: var(--ink-2); font-size: 0.8125rem; }

.sheet tbody th { font-weight: 400; }

/* Status: never colour alone. A dot and the word, always both. */
.state { display: block; white-space: nowrap; }

.state::before {
    content: "";
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    margin-right: 0.4rem;
    vertical-align: 0.05rem;
}

.state--on::before { background: var(--grant); }

.state--off { color: var(--refuse); }

.state--off::before { background: var(--refuse); }

/*
   Fix round 1: this carried its own font-size while its two siblings did not, which was invisible
   while it only ever labelled a secondary annotation ("No authenticator yet") beside a full-size
   primary state. The Merchants screen's status column made it a primary state in its own right
   (Published), sitting beside .state--on and .state--off in the same cell context - three peers that
   now need to read as the same kind of thing, not two full-size ones and a visibly smaller third.
*/
.state--warn { color: var(--caution); }

.state--warn::before { background: var(--caution); }

/*
   The neutral member of the trio a shop's lifecycle actually is - Draft -> Published -> Active is a
   progression, not a health signal, so Draft gets no colour opinion at all rather than borrowing
   .state--off's red, which read as "broken" for the ordinary state every merchant starts in.
*/
.state--neutral { color: var(--ink-2); }

.state--neutral::before { background: var(--ink-2); }

.do { white-space: nowrap; text-align: right; }

.do .btn + .btn { margin-left: 0.4rem; }

.do__self { color: var(--ink-2); font-size: 0.8125rem; }

/* ---------- choices ---------- */

fieldset { border: 0; margin: 0 0 1.15rem; padding: 0; }

legend { padding: 0; font-weight: 500; }

.choice {
    display: grid;
    grid-template-columns: 1.05rem minmax(0, 1fr);
    gap: 0.7rem;
    align-items: start;
    max-width: 40rem;
    padding: 0.55rem 0;
    cursor: pointer;
}

.choice + .choice { border-top: 1px solid var(--rule); }

.choice input[type="radio"] {
    width: 1.05rem;
    height: 1.05rem;
    margin: 0.25rem 0 0;
    accent-color: var(--signal);
}

.choice b { font-weight: 500; }

.choice .why { display: block; font-size: 0.8125rem; color: var(--ink-2); }

/* ---------- small helpers ---------- */

.pushed { margin-top: 2rem; }

.msg-after { margin: 1rem 0 0; }

.inline-form { display: inline; }

/* The activation-fee edit on /admin/markets: a symbol, a number field and a Save button on one
   line, sized to sit inside the sheet's already-narrow "Activation fee" column. */
.fee-form { display: inline-flex; align-items: center; gap: 0.35rem; }
.fee-form .fee-input { width: 6.5rem; min-width: 5rem; text-align: right; }
.fee-affix { color: var(--ink-2); font-size: 0.8125rem; }

/* ---------- secrets shown once ---------- */

.secret {
    display: block;
    background: var(--ground);
    border: 1px solid var(--rule-2);
    border-radius: var(--r);
    padding: 0.7rem 0.85rem;
    font-size: 1.0625rem;
    letter-spacing: 0.08em;
    /* Wrap between the four-character groups, never inside one: a secret split mid-group is a
       secret somebody types wrong. */
    word-break: normal;
    overflow-wrap: break-word;
    user-select: all;
}

.uri {
    display: block;
    margin-top: 0.5rem;
    font-size: 0.8125rem;
    word-break: break-all;
}

.codes {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem 1.25rem;
    margin: 1rem 0 0;
    padding: 0;
    list-style: none;
    counter-reset: code;
}

.codes li {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    padding: 0.35rem 0.6rem;
    background: var(--paper);
    border: 1px solid var(--rule-2);
    border-radius: var(--r);
    font-size: 1.0625rem;
    letter-spacing: 0.06em;
}

/* The codes are a numbered list because they are a checklist to tick off, not a sequence to follow. */
.codes li::before {
    counter-increment: code;
    content: counter(code);
    color: var(--ink-2);
    font-size: 0.75rem;
    font-family: "IBM Plex Sans", system-ui, sans-serif;
    letter-spacing: 0;
    min-width: 1.1rem;
}

.steps { margin: 0; padding-left: 1.35rem; }

.steps > li { margin-bottom: 1.1rem; }

.steps > li::marker { color: var(--ink-2); font-weight: 600; }

/* ---------- the overview's dashboard ---------- */

/*
   The hero, and the reason this page was rebuilt. It used to open with two lists of the reader's own
   grants and put the platform underneath them, which is a description of whoever is looking rather
   than of what they came to find out. This is one sentence saying where things stand.

   A sentence rather than a row of cards because the platform has two merchants: a card reading "2"
   is a number pretending to be information, while "Two shops trading. One waiting to pay." is the
   whole morning briefing. The measure is short on purpose, so a longer sentence breaks into two or
   three lines and stays a shape rather than becoming a paragraph.
*/
.standing {
    max-width: 26ch;
    font-size: 1.75rem;
    line-height: 1.25;
}

/*
   The work list. The one element on this page given any emphasis at all, and it takes it the way the
   sign-in panel does - a 3px rule along one edge of a white surface. No shadow, no tint, no second
   radius: an instrument, not an app.
*/
.work { border-top: 3px solid var(--signal); }

.work h2 { margin-bottom: 1rem; }

/*
   This section's three non-list states are read rather than glanced at - an operator deciding there
   is nothing to do this morning is reading a whole sentence, and .hint's 13px is the size the rest
   of the portal uses for a footnote under a table. The class is kept because every empty state in
   the portal is a .hint and consistency there is worth more than a second class name; only the size
   is taken back.
*/
.work .hint { margin: 0; max-width: 52ch; font-size: 1rem; }

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

/*
   Three columns: who, what is stuck, and how long it has been stuck. The name is a link and comes
   first because the row exists to be opened; the date is last and quiet because it changes how
   urgent a row is without ever being the reason to click it.
*/
.worklist li {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr) auto;
    gap: 0.3rem 1.5rem;
    align-items: baseline;
    padding: 0.75rem 0;
}

.worklist li + li { border-top: 1px solid var(--rule); }

.worklist li:first-child { padding-top: 0; }

.worklist li:last-child { padding-bottom: 0; }

.worklist__shop { font-weight: 500; }

.worklist__since {
    color: var(--ink-2);
    font-size: 0.8125rem;
    text-align: right;
    white-space: nowrap;
}

/*
   The counts, demoted. Label and figure on one line at reading size - the deliberate opposite of
   .stats, which sets a 1.625rem number above its label and is exactly what a dashboard of cards
   looks like. Both exist because the merchant, order and product screens genuinely do lead with a
   figure; this screen leads with a sentence, and these are the footnote to it.
*/
.tally {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 2rem;
    margin: 0;
}

.tally > div { display: flex; align-items: baseline; gap: 0.5rem; }

.tally dt { color: var(--ink-2); }

.tally dd {
    margin: 0;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* The recent tail sits on the same rule as the figures above it, being the same kind of aside. */
.recent {
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--rule-2);
}

.recentlist { margin: 0.75rem 0 0; padding: 0; list-style: none; }

.recentlist li {
    display: grid;
    grid-template-columns: 11rem minmax(0, 1fr) minmax(0, 1fr) auto;
    gap: 0.2rem 1.25rem;
    align-items: baseline;
    padding: 0.4rem 0;
}

.recentlist li + li { border-top: 1px solid var(--rule); }

/*
   The times, in the same face as everything beside them. A column of six is held straight by tabular
   figures - the device .tally already uses on its counts - rather than by reaching for the mono face,
   which has one job in this portal and this is not it. The audit screen and a shop's own history set
   their timestamps in the sans face for the same reason.
*/
.recentlist__when {
    font-size: 0.8125rem;
    color: var(--ink-2);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.recentlist__who { color: var(--ink-2); }

.recentlist__shop { white-space: nowrap; }

/*
   The grant sheet, folded away. The same disclosure as .by-hand on the enrolment screen, for the
   same reason: it stays one click from whoever needs it, and it stops being the first thing the page
   says. There is no JavaScript in this portal, so <details> is the mechanism rather than a choice.
*/
.grants {
    margin-top: 2.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--rule-2);
}

.grants > summary {
    cursor: pointer;
    padding: 0.4rem 0;
    color: var(--ink-2);
    font-weight: 500;
}

.grants[open] > summary { margin-bottom: 1.25rem; }

/* ---------- overview ---------- */

.bands { display: flex; flex-wrap: wrap; gap: 2.5rem; }

.bands h2 { margin-bottom: 0.75rem; }

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

.bandlist li {
    display: grid;
    grid-template-columns: 1.05rem minmax(0, 1fr);
    gap: 0.7rem;
    align-items: start;
    padding: 0.45rem 0;
    max-width: 34rem;
}

.bandlist li + li { border-top: 1px solid var(--rule); }

.bandlist .off { color: var(--ink-2); }

.bandlist b { font-weight: 500; }

.bandlist .yn { color: var(--ink-2); font-size: 0.8125rem; margin-left: 0.4rem; }

.bandlist .why { display: block; font-size: 0.8125rem; color: var(--ink-2); }

.figures {
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--rule-2);
}

.figures h3 {
    margin: 1.5rem 0 0.5rem;
    font-size: 0.9375rem;
    font-weight: 600;
}

.figures .hint { margin: 0; color: var(--ink-2); }

/* Three counts, read as a shape before they are read as numbers - the same idea as .mark on the
   grant sheet, applied to figures instead of flags. */
.stats {
    display: flex;
    flex-wrap: wrap;
    gap: 1.75rem;
    margin: 0;
}

.stat { min-width: 6rem; }

.stat dt {
    font-size: 0.8125rem;
    color: var(--ink-2);
}

.stat dd {
    margin: 0.15rem 0 0;
    font-size: 1.625rem;
    font-weight: 600;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}

.revenue {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.revenue li { font-variant-numeric: tabular-nums; }

.revenue b { font-weight: 600; margin-right: 0.4rem; }

.next {
    margin-top: 2rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--rule-2);
    color: var(--ink-2);
}

.next p { max-width: 56ch; }

/* ---------- merchant filters ---------- */

/*
   A plain GET form - there is no JavaScript anywhere in this portal, so "filter" means "submit and
   reload" and the values it submitted are what has to reappear in these same fields afterwards.
*/
.filters {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 1rem 1.25rem;
    margin-bottom: 1.75rem;
}

.filters .field { margin-bottom: 0; }

.filters .field--search { flex: 1 1 16rem; min-width: 16rem; }

.filters .field--country { width: 8rem; }

.filters .field--status { width: 12rem; }

.sheet .num { text-align: right; font-variant-numeric: tabular-nums; }

/*
   The audit log's detail column holds JSON another code path wrote, not this page's own copy - it
   can be long, and it can be malformed. overflow-wrap: anywhere is what actually stops one long value
   stretching the row: it lets a break land anywhere in the string, not just at a space, which compact
   JSON has few of. max-width does nothing on its own here - a <td>'s width is not constrained by it
   under the browser's default (auto) table layout, Chrome included - so if a value somehow still ran
   the row wide, it is .sheetwrap's own overflow-x: auto that is the real fallback, scrolling the sheet
   sideways in its own wrapper rather than the page doing so. Keep overflow-wrap and .sheetwrap; do not
   assume max-width is holding anything up.
*/
.sheet .detail {
    max-width: 22rem;
    overflow-wrap: anywhere;
    color: var(--ink-2);
    font-size: 0.8125rem;
}

/* ---------- narrow windows ---------- */

/*
   Desktop-first: this portal is used on laptops and the grant sheet needs the width. Below 900px it
   stays usable rather than pretty - the sheet scrolls sideways inside its own wrapper instead of
   pushing the page.
*/
@media (max-width: 900px) {
    .acting { flex-wrap: wrap; padding: 0.65rem 1rem; }

    .acting__out { margin-left: 0; }

    .top__in { flex-wrap: wrap; gap: 1rem; padding: 0.75rem 1rem; }

    .top__nav { gap: 1.1rem; }

    .top__nav a { padding: 0.4rem 0; }

    .main { padding: 1.5rem 1rem 4rem; }

    .focus { padding: 2rem 1rem 4rem; }

    .bands { gap: 1.75rem; }

    .worklist li, .recentlist li { grid-template-columns: minmax(0, 1fr); }

    .worklist__since { text-align: left; }

    .codes { grid-template-columns: minmax(0, 1fr); }

    .filters { align-items: stretch; }

    .filters .field--country, .filters .field--status { width: auto; }
}

/* ---------- print ---------- */

/*
   Recovery codes and a temporary password are shown once and never again, so Ctrl+P has to produce
   something worth keeping. Everything that is not the codes goes away.
*/
@media print {
    body { background: #FFFFFF; }

    /*
       Hide what cannot be used on paper, and nothing else. An earlier version hid every form and
       every field globally, which printed the "Add an administrator" heading above the empty space
       where its form had been. Whole blocks that are only for pressing carry .no-print instead.
    */
    .acting, .top, .btn, .panel__foot, .no-print { display: none !important; }

    .focus, .main { max-width: none; padding: 0; }

    .panel { border: 0; padding: 0; }

    /* The sheet must not be clipped at the paper's edge by its own scroll container. */
    .sheetwrap { overflow: visible; }

    .codes li { border-color: #999999; }
}

/*
   Enrolment's primary action. Full width and tall because it is tapped on a phone, one-handed, by
   somebody who has just been told their password alone will not get them in - and because the
   alternative to tapping it is transcribing a thirty-two character key by hand.
*/
.btn--wide {
    display: block;
    width: 100%;
    text-align: center;
    padding: 0.85rem 1rem;
    min-height: 3rem;
    text-decoration: none;
}

/*
   The key, folded away. It is still the fallback for a browser that is not on the phone, so it stays
   reachable in one click - but it is no longer the first thing the page offers, because a key that
   is typed is a key that can be mistyped.
*/
.by-hand > summary {
    cursor: pointer;
    padding: 0.4rem 0;
    color: var(--ink-2);
}

.by-hand[open] > summary { margin-bottom: 0.35rem; }
