/* A.P.E.S. — the house style of a corporation that does not think of itself as
 * a game.
 *
 * THE BRIEF. A connected game is lo-fi/hi-res: near-black, emitted neon #29abff
 * and #ff2dd6, stark mechanics. A.P.E.S. has to be unmistakably the same
 * universe and unmistakably not the same thing, because the moment it works is
 * the moment a player wonders "how is A.P.E.S. a real thing I'm supposed to log
 * in to?"
 *
 * So where the game is a SCREEN, A.P.E.S. is a DOCUMENT. The game glows; the
 * corporation absorbs. Bond cream, one oxide ink, one cool accent, hairline
 * rules, tabular figures, a stamp that comes down once. Neither one decorates —
 * that is what makes them one studio.
 *
 * The light ground is also functionally right rather than merely contrarian:
 * the pairing placard on a cabinet has to scan from two metres across a dark
 * room, and dark ink on a bright field is the best scanning target there is. It
 * is the one moment in the whole game where the screen goes bright, which is
 * itself the shock.
 *
 * THE TYPOGRAPHIC LAW: if a machine cares about it, it is mono. If a human
 * wrote it, it is sans. A player learns this in four seconds and thereafter
 * knows at a glance which parts of the screen are data. The corollary matters
 * more than the rule: PROSE IS NEVER MONO. A paragraph of monospace on a phone
 * in a dark bar is a small act of hostility.
 *
 * NO WEBFONT, and this is a deliberate refusal. The brand direction called for
 * Archivo and IBM Plex Mono from Google Fonts. On any other property that would
 * be fine; on the login screen for every account in the universe it would make
 * fonts.googleapis.com a rendering dependency of authentication and force
 * `style-src` to admit an external origin. An identity server does not take
 * that trade for a typeface. The system stacks below honour the same law at
 * zero bytes and zero requests, and the upgrade path is open: self-host the two
 * subsetted woff2 files on this same distribution (~40KB, one commit) and the
 * CSP never has to change, because they would be served from 'self'.
 *
 * A NOTE ON CACHING, because it cost an hour. Asset URLs carry `?v=<hash of
 * these bytes>` and are served `immutable` for a year. That is only sound if
 * the edge keys its cache on that query string, and CloudFront's
 * `Managed-CachingOptimized` policy does NOT — so for one deploy every version
 * of this file collapsed onto a single cached object and the browser was handed
 * last week's CSS under this week's URL, with a year to live. infra/site.tf now
 * defines a cache policy that whitelists `v`. If a change to this file ever
 * appears not to deploy, check that first and check the origin with curl before
 * suspecting anything else.
 *
 * EVERY COLOUR PAIR IS MEASURED. The ratios in the comments were computed with
 * license-core.mjs's own WCAG 2.2 implementation — the same code that polices
 * player colours. Text pairs clear 4.5:1; anything that bounds a control clears
 * 3:1 per SC 1.4.11. If you change a value, re-run the numbers.
 */

/* --- Tokens --------------------------------------------------------------
 *
 * Three theme states, and all three are wired: the full palette on bare :root,
 * the dark overrides under prefers-color-scheme guarded so an explicit light
 * choice still wins, and the same overrides again under [data-theme="dark"] so
 * a toggle wins in both directions. No colour is ever defined only inside a
 * media query.
 */

:root {
  color-scheme: light dark;

  /* Grounds */
  --ap-paper: #f2eee4; /* page ground — bond cream */
  --ap-paper-2: #e4ded0; /* manila: cards, insets, input wells */

  /* Inks */
  --ap-ink: #16130f; /* 15.98:1 on paper — body, headings, all data */
  --ap-ink-2: #4a423a; /* 8.50:1 — labels, fine print, secondary */
  --ap-oxide: #a8320f; /* 5.79:1 — THE corporate ink: stamps, seal, errors */
  --ap-station: #1f5f5c; /* 6.36:1 — links; the one cool hue */
  --ap-void: #7e1111; /* 9.18:1 — ON HOLD and withdrawal only */
  --ap-amber: #e8b62c; /* 1.62:1 — FILL ONLY, never text. ink on it = 9.84:1 */

  /* Rules */
  --ap-rule: #6e6759; /* 4.84:1 — anything that bounds a control */
  --ap-hairline: #c9c2ae; /* 1.53:1 — decorative only, never the sole signal */

  --ap-on-oxide: #f2eee4; /* 5.79:1 on oxide */
  --ap-on-ink: #f2eee4; /* 15.98:1 on ink */

  /* Type. The law: mono for machine-readable, sans for everything human. */
  --ap-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, sans-serif;
  --ap-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "DejaVu Sans Mono", "Liberation Mono", monospace;

  /* 4px scale. The strictness is the aesthetic: machine-set type on a ruled
   * sheet. Every vertical measure is a step on this. */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;
  --sp-8: 64px;
  --sp-9: 96px;

  --ap-measure: 34rem;
  --ap-radius: 2px; /* paper has edges, not glows */
}

/* Dark is not a mode here, it is the carbon duplicate: the same document struck
 * through carbon paper onto slate. Token ROLES are identical, so every rule
 * below holds by construction. It is not optional — this page gets used at 1am
 * in a dark bar, and a full-brightness cream screen there gets the phone put
 * away. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ap-paper: #191714;
    --ap-paper-2: #241f1a;
    --ap-ink: #efe9da; /* 14.77:1 */
    --ap-ink-2: #b0a695; /* 7.44:1 */
    --ap-oxide: #ff7a4d; /* 6.94:1 */
    --ap-station: #63bdb6; /* 8.08:1 */
    --ap-void: #ff6b6b; /* 6.45:1 */
    --ap-amber: #f2c33c;
    --ap-rule: #8a8271; /* 4.70:1 */
    --ap-hairline: #3a352e;
    --ap-on-oxide: #191714; /* 6.94:1 on oxide */
    --ap-on-ink: #191714;
  }
}

:root[data-theme="dark"] {
  --ap-paper: #191714;
  --ap-paper-2: #241f1a;
  --ap-ink: #efe9da;
  --ap-ink-2: #b0a695;
  --ap-oxide: #ff7a4d;
  --ap-station: #63bdb6;
  --ap-void: #ff6b6b;
  --ap-amber: #f2c33c;
  --ap-rule: #8a8271;
  --ap-hairline: #3a352e;
  --ap-on-oxide: #191714;
  --ap-on-ink: #191714;
}

/* --- Reset ---------------------------------------------------------------- */

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

html {
  /* Never below 100%. A login screen is the last place on earth to override
   * somebody's chosen text size. */
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
  font-variant-numeric: tabular-nums;
}

body {
  margin: 0;
  /* Explicit, always: the ground is the first thing that says "document". */
  background-color: var(--ap-paper);
  color: var(--ap-ink);
  font-family: var(--ap-sans);
  font-size: 17px;
  line-height: 1.55;
  /* The faintest tooth, so the ground reads as stock rather than as a hex
   * value. One gradient, no image request. */
  background-image: repeating-linear-gradient(
    0deg,
    rgb(0 0 0 / 1.5%) 0 1px,
    transparent 1px 3px
  );
}

/* Nothing in A.P.E.S. is ever set below 12px. This is the largest concession
 * the aesthetic makes and it is not negotiable: parody wants 8-point type, and
 * the rules, the rhythm and the tabular figures do that work instead. */

/* --- The signature device: the hazard band -------------------------------
 *
 * Amber chevrons under an oxide bar. It sits at the top of every page and above
 * every consequential action, and it is the one mark that makes an A.P.E.S.
 * page recognisable from across a room. Pure CSS — no image, no request, scales
 * to any width.
 */

.band {
  height: var(--sp-3);
  border: 0;
  margin: 0;
  background-color: var(--ap-amber);
  background-image: repeating-linear-gradient(
    -45deg,
    var(--ap-oxide) 0 var(--sp-2),
    transparent var(--sp-2) var(--sp-4)
  );
}

/* The recruitment line — the single sanctioned exclamation mark in the entire
 * product, and the only place the corporation says "us". The gap between this
 * poster and the form below it is the whole joke. */
.band-motto {
  /* max-width: none, because the global `p` rule caps prose at 62ch and this is
   * not prose — it is a painted band. Without this the poster stops two-thirds
   * of the way across the page and reads as a broken element rather than as the
   * one loud thing on the sheet. */
  max-width: none;
  background-color: var(--ap-oxide);
  color: var(--ap-on-oxide); /* 5.79:1 */
  font-family: var(--ap-sans);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-align: center;
  padding: var(--sp-2) var(--sp-4);
}

/* --- Layout --------------------------------------------------------------- */

.sheet {
  max-width: var(--ap-measure);
  margin: 0 auto;
  padding: var(--sp-6) var(--sp-4) var(--sp-9);
}

.masthead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  flex-wrap: wrap;
  padding-block: var(--sp-4);
  border-bottom: 1px solid var(--ap-hairline);
}

/* The mark, then the name. The mark carries the identity at a glance and the
 * name carries it for anyone who has not learned the mark yet — which, on an
 * identity server a stranger has just been sent to, is everyone. */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  color: inherit;
  text-decoration: none;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.masthead-mark {
  width: 22px;
  height: 22px;
  flex: none;
  color: var(--ap-oxide);
}

/* The full corporate name, set small and unbroken. It is a joke that gets
 * funnier the more seriously it is typeset. */
.entity {
  margin: 0;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ap-ink-2); /* 8.50:1 */
}

/* --- Type ----------------------------------------------------------------- */

h1 {
  /* Sentence case, against every instinct the aesthetic has. Uppercase at 34px
   * on a phone is measurably slower to read, and some screen readers spell it
   * out letter by letter. Uppercase is quarantined to labels at 12px, where it
   * is a texture rather than a message. */
  font-size: clamp(24px, 6vw, 34px);
  font-weight: 700;
  line-height: 1.15;
  margin: 0 0 var(--sp-4);
}

h2 {
  font-size: clamp(19px, 4.5vw, 22px);
  font-weight: 700;
  margin: var(--sp-7) 0 var(--sp-3);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--ap-hairline);
}

p {
  margin: 0 0 var(--sp-4);
  max-width: 62ch;
}

a {
  color: var(--ap-station); /* 6.36:1 */
  text-underline-offset: 0.2em;
}

.lede {
  font-size: 19px;
}

.fine {
  font-size: 14px;
  line-height: 1.6;
  color: var(--ap-ink-2);
}

/* A block header — the small uppercase rule-caption that labels a section of
 * the form. Never an accessible name: it is either a real <label for> or it is
 * aria-hidden beside a properly announced value. */
.block-header {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ap-ink-2);
  margin: 0 0 var(--sp-2);
}

/* Institutional metadata: form numbers, clause references, revision codes.
 * These carry no information a user needs, which is precisely why they must
 * never be mistaken for information a user needs. Never in the tab order. */
.stamp-line {
  font-family: var(--ap-mono);
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ap-ink-2);
}

/* Machine-readable values: operator numbers, codes, hex, dates, references.
 * The other half of the typographic law. */
.data {
  font-family: var(--ap-mono);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* --- Focus ---------------------------------------------------------------- */

/* Two rings, so it survives on cream, on ink and on oxide alike. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--ap-oxide);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px var(--ap-paper);
}

/* --- Forms ---------------------------------------------------------------
 *
 * This is where the joke stops. Somebody is trying to log in, on a phone, in a
 * loud room, possibly holding a drink. Labels are visible and permanent — never
 * a placeholder, which disappears exactly when it is needed. Targets are 44px.
 * Errors say what to do next, in plain English, with no euphemism anywhere near
 * them.
 */

.field {
  display: block;
  margin-bottom: var(--sp-5);
}

.field > .label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ap-ink-2);
  margin-bottom: var(--sp-2);
}

.field > .hint {
  font-size: 14px;
  color: var(--ap-ink-2);
  margin: var(--sp-2) 0 0;
}

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="color"],
select,
textarea {
  width: 100%;
  min-height: 44px;
  padding: var(--sp-3);
  font-family: var(--ap-sans);
  /* 16px minimum, always. Below it, iOS Safari zooms the page on focus — and
   * in a bar, at the moment of typing a code, that is a disaster. */
  font-size: 16px;
  color: var(--ap-ink);
  background-color: var(--ap-paper-2);
  border: 2px solid var(--ap-rule); /* 4.84:1 — bounds a control, SC 1.4.11 */
  border-radius: var(--ap-radius);
}

input::placeholder {
  color: var(--ap-ink-2);
  opacity: 1; /* Firefox dims placeholders by default, taking them below AA */
}

/* The cabinet code and the gate pass. Both are machine data, so both are mono;
 * both are wide-tracked so eight characters read as eight characters at arm's
 * length. Paste is never blocked (WCAG 2.2 SC 3.3.8) and neither is validated
 * on keystroke — nothing is rejected until submit. */
.code-input {
  font-family: var(--ap-mono);
  font-weight: 700;
  font-size: clamp(24px, 9vw, 34px);
  letter-spacing: 0.14em;
  text-align: center;
  text-transform: uppercase;
  min-height: 56px;
}

/* --- Buttons -------------------------------------------------------------
 *
 * Verbs stay plain English. The fiction supplies nouns and never verbs, which
 * is the single rule that keeps this from becoming a themed-restaurant menu and
 * is why every button here is structurally immune to the joke.
 */

/* The primary action is OXIDE, not ink.
 *
 * It was ink, which is correct in light mode — a dark block on cream reads
 * unmistakably as the thing to press. In the carbon duplicate the same token
 * inverts to cream, and a pale block on a dark page reads as a panel rather
 * than a control. Reported exactly that way: "an ambiguous white colour in all
 * states".
 *
 * Oxide is the corporation's one ink and is the same colour in both themes, so
 * the primary action is now the only saturated thing on the page in either. It
 * clears 5.79:1 in light and 6.94:1 in carbon against its own label. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-3) var(--sp-5);
  font-family: var(--ap-sans);
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-decoration: none;
  cursor: pointer;
  border: 2px solid var(--ap-oxide);
  border-radius: var(--ap-radius);
  background-color: var(--ap-oxide);
  color: var(--ap-on-oxide);
  transition: background-color 120ms ease, border-color 120ms ease, opacity 120ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .btn {
    transition: none;
  }
}

/* Pressable, and visibly so. */
.btn:hover {
  background-color: color-mix(in srgb, var(--ap-oxide) 85%, var(--ap-ink));
  border-color: color-mix(in srgb, var(--ap-oxide) 85%, var(--ap-ink));
}

.btn:active {
  transform: translateY(1px);
}

/* Retained for the consent screen, which names its primary action explicitly
 * rather than relying on the default. */
.btn--oxide {
  background-color: var(--ap-oxide);
  border-color: var(--ap-oxide);
  color: var(--ap-on-oxide);
}

/* NOT READY YET.
 *
 * `:has()` lets the form tell the button that a required field is still empty
 * or malformed, with no script involved. It is a HINT, not a lock: the button
 * stays focusable and pressable, so pressing it triggers the browser's own
 * validation message, which is what tells somebody WHY nothing happened. A
 * genuinely disabled button says "no" and refuses to say why, and is invisible
 * to a screen reader's tab order.
 *
 * Browsers without :has() simply always show the ready state, which is exactly
 * the behaviour that shipped before. */
form:has(input:required:invalid) .btn[type="submit"],
form:has(input:required:invalid) .btn:not([type]) {
  background-color: transparent;
  color: var(--ap-ink-2);
  border-color: var(--ap-rule);
}

/* Working. The label is swapped by /assets/apes.js; this is the look. */
.btn.is-busy {
  background-color: color-mix(in srgb, var(--ap-oxide) 60%, var(--ap-paper));
  border-color: color-mix(in srgb, var(--ap-oxide) 60%, var(--ap-paper));
  color: var(--ap-ink);
  cursor: progress;
}

/* A field being submitted is read-only, not disabled — it still submits its
 * value and keeps its place in the tab order. It should look settled rather
 * than broken. */
input:read-only:not([type="hidden"]),
textarea:read-only {
  background-color: transparent;
  border-color: var(--ap-hairline);
  color: var(--ap-ink-2);
  cursor: default;
}

form[aria-busy="true"] {
  cursor: progress;
}

.btn--quiet {
  background-color: transparent;
  color: var(--ap-ink);
  border-color: var(--ap-rule);
}

.btn--block {
  width: 100%;
}

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

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-5);
}

/* Deny sits beside Approve at equal visual weight. A destructive-looking deny
 * that a user hesitates over is a user who approves something they did not
 * mean to approve. */
.actions--decision .btn {
  flex: 1 1 12rem;
}

/* --- Notices -------------------------------------------------------------- */

.notice {
  border-left: 4px solid var(--ap-rule);
  background-color: var(--ap-paper-2);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-5);
  border-radius: var(--ap-radius);
}

.notice--error {
  border-left-color: var(--ap-oxide);
}

.notice--held {
  border-left-color: var(--ap-void);
}

/* Caution — the contrast check, and anything else that is a finding rather than
 * a refusal.
 *
 * --ap-amber is the palette's caution hue but it is a FILL token: against this
 * notice's own manila ground it measures 1.40:1, a bar nobody can see, and a
 * warning about legibility that is itself illegible is worse than no bar at
 * all. So the rule takes amber carried down to the weight its siblings already
 * hold — 5.16:1 on manila light (--ap-oxide is 5.01), 6.33:1 dark (--ap-oxide
 * is 6.33), both clear of the 3:1 floor for a non-text signal.
 *
 * Kept as a local custom property rather than a palette token because caution
 * is not a role the rest of the product has: one component wants this colour,
 * and a token invites a second use nobody measured. Light is declared on the
 * bare rule so no colour lives only inside a media query, and both dark guards
 * are present so the toggle wins in either direction. */
.notice--warn {
  --notice-caution: #7a5200;
  border-left-color: var(--notice-caution);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .notice--warn {
    --notice-caution: #c99a2e;
  }
}

:root[data-theme="dark"] .notice--warn {
  --notice-caution: #c99a2e;
}

/* Colour is never the only signal — every notice is also prefixed with a word,
 * which is the same reason the game must never encode anything in colour
 * alone. */
.notice > .notice-label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ap-ink-2);
  margin-bottom: var(--sp-1);
}

/* --- The license ---------------------------------------------------------
 *
 * THE LIVERY EXCEPTION, and it is the one rule that welds A.P.E.S. to the
 * concessions it licenses: the corporation prints in one ink, and the only
 * saturated colour anywhere in the product is the two chips the operator chose.
 *
 * The company is monochrome. The person is the colour.
 *
 * Both default livery values fail as text on cream (#29abff = 2.17:1,
 * #ff2dd6 = 2.75:1), so a livery colour is NEVER text. It appears only as a
 * filled chip and a filled rig stroke, always with the hex printed adjacent in
 * --ap-ink, always inside a 1px --ap-rule border so a pale livery cannot
 * dissolve into the paper.
 */

.license {
  position: relative;
  border: 2px solid var(--ap-ink);
  border-radius: var(--ap-radius);
  background-color: var(--ap-paper);
  overflow: hidden;
  /* A card, not a panel: a fixed aspect near ID-1 (the credit-card ratio) so it
   * reads as an object that exists rather than as a box the page happened to
   * draw. It gives that up below 30rem, where honouring a ratio would mean
   * shrinking the call sign past legibility — the document survives, the
   * proportion does not. */
  container-type: inline-size;
}

/* The guilloche: the fine repeating ground printed under every real credential,
 * which exists to be annoying to photocopy. Two gradients, no image request,
 * and faint enough that it never fights the data on top of it. */
.license::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.5;
  background-image:
    repeating-linear-gradient(45deg, var(--ap-hairline) 0 1px, transparent 1px 7px),
    repeating-linear-gradient(-45deg, var(--ap-hairline) 0 1px, transparent 1px 11px);
}

.license > * {
  position: relative; /* above the guilloche */
}

.license-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 2px solid var(--ap-ink);
  background-color: var(--ap-paper-2);
}

.license-mark {
  width: 34px;
  height: 34px;
  color: var(--ap-ink);
  flex: none;
}

/* Set as text rather than shipped as an image of text: an <img> of the lockup
 * bakes its type at one size, and at this header's width that put the strapline
 * near 5px — under the 12px floor the bible calls non-negotiable. */
.license-wordmark {
  margin: 0;
  margin-right: auto;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 0.2em;
  line-height: 1.1;
}

.license-wordmark span {
  display: block;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ap-ink-2);
}

.license-form {
  margin: 0;
  white-space: nowrap;
}

.license-body {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-4);
  padding: var(--sp-4);
  align-items: start;
}

/* The portrait berth. On a real card this is a face; here it is the two things
 * that identify an operator at two hundred metres in a dark arena — their
 * livery and the silhouette of their rig. */
.license-portrait {
  position: relative;
  width: 88px;
  height: 108px;
  border: 1px solid var(--ap-rule);
  background-color: var(--ap-paper-2);
  display: grid;
  place-items: center;
  overflow: hidden;
}

.license-livery {
  position: absolute;
  inset: 0;
  /* The operator's two colours, and the only saturated thing on the document.
   * A hard split rather than a blend, so it survives a greyscale print — which
   * validateColorPair is what guarantees. */
  background-image: linear-gradient(
    160deg,
    var(--livery-hull, var(--ap-ink)) 0 50%,
    var(--livery-trim, var(--ap-ink-2)) 50% 100%
  );
  opacity: 0.9;
}

.license-rig {
  position: relative;
  width: 56px;
  height: 52px;
  color: var(--ap-paper);
  filter: drop-shadow(0 0 1px rgb(0 0 0 / 45%));
}

/* An empty berth says so, rather than drawing equipment nobody was issued. */
.license-rig--none {
  position: relative;
  width: 56px;
  height: 52px;
  border: 1px dashed var(--ap-rule);
}

.license-fields {
  margin: 0;
  display: grid;
  gap: var(--sp-3);
  min-width: 0;
}

.license-fields > div {
  min-width: 0;
}

.license-fields dt {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ap-ink-2);
}

.license-fields dd {
  margin: 2px 0 0;
  font-size: 16px;
  overflow-wrap: anywhere;
}

.license-callsign {
  font-size: clamp(20px, 6cqi, 26px);
  font-weight: 700;
  line-height: 1.15;
}

.license-number {
  font-weight: 600;
  letter-spacing: 0.06em;
}

/* The machine-readable zone. Monospace by law of the typographic rule — this is
 * the most machine-readable thing on the document — and allowed to scroll on
 * its own rather than wrap, because an MRZ that wraps is not an MRZ. */
.license-mrz {
  margin: 0;
  padding: var(--sp-2) var(--sp-4) var(--sp-3);
  border-top: 1px dashed var(--ap-rule);
  background-color: var(--ap-paper-2);
  font-size: 13px;
  letter-spacing: 0.08em;
  white-space: nowrap;
  overflow-x: auto;
  color: var(--ap-ink);
}

/* The seal is a STAMP, so it has to look pressed rather than printed: full
 * strength oxide, sitting over the fields the way ink sits over type it was
 * struck onto afterwards. The first attempt used 0.85 opacity and hairline
 * strokes and read as a smudge at card size. */
.license-seal {
  position: absolute;
  right: var(--sp-4);
  bottom: var(--sp-5);
  width: 104px;
  height: 104px;
  color: var(--ap-oxide);
  transform: rotate(-7deg);
  pointer-events: none;
  /* Multiply so the fields beneath show through, which is what makes it read as
   * ink on a document rather than a sticker on top of one. Dropped in the
   * carbon duplicate, where multiply against a dark ground erases it. */
  mix-blend-mode: multiply;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .license-seal {
    mix-blend-mode: normal;
    opacity: 0.92;
  }
}

:root[data-theme="dark"] .license-seal {
  mix-blend-mode: normal;
  opacity: 0.92;
}

/* Below the width where a seal and a field column can share a row, the seal
 * steps back to being a watermark rather than overlapping the data. */
@container (max-width: 26rem) {
  .license-seal {
    opacity: 0.14;
    right: 50%;
    transform: translateX(50%) rotate(-7deg);
  }
}

.license--held {
  border-style: dashed;
  border-color: var(--ap-void);
}

.license--held .license-head {
  border-bottom-color: var(--ap-void);
}

/* --- The seal ------------------------------------------------------------- */

.seal {
  width: 88px;
  height: 88px;
  /* Pressed by hand, so it is never quite square to the page. */
  transform: rotate(-7deg);
}

.seal--watermark {
  position: absolute;
  right: calc(var(--sp-4) * -1);
  bottom: calc(var(--sp-4) * -1);
  width: 128px;
  height: 128px;
  opacity: 0.1;
  pointer-events: none;
}

/* The stamp comes down once, and only if motion is welcome. */
@media (prefers-reduced-motion: no-preference) {
  .seal--strike {
    animation: seal-strike 380ms cubic-bezier(0.2, 0.9, 0.3, 1) both;
  }
  @keyframes seal-strike {
    from {
      transform: rotate(-7deg) scale(2.4);
      opacity: 0;
    }
    to {
      transform: rotate(-7deg) scale(1);
      opacity: 1;
    }
  }
}

/* --- Records -------------------------------------------------------------- */

.record {
  width: 100%;
  border-collapse: collapse;
  font-size: 16px;
}

.record th,
.record td {
  text-align: left;
  padding: var(--sp-3) var(--sp-2);
  border-bottom: 1px solid var(--ap-hairline);
  vertical-align: top;
}

.record th {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ap-ink-2);
}

.record td.data {
  font-family: var(--ap-mono);
}

/* Wide tables scroll inside their own box; the page body never scrolls
 * sideways. */
.scroller {
  overflow-x: auto;
}

/* --- The perforation ------------------------------------------------------
 *
 * A tear line. Used where the document is meant to come apart: between the
 * license and its counterfoil, and above the fine print.
 */

.perf {
  height: 1px;
  border: 0;
  margin: var(--sp-5) 0;
  background-image: repeating-linear-gradient(
    to right,
    var(--ap-rule) 0 6px,
    transparent 6px 12px
  );
}

/* --- Colophon ------------------------------------------------------------- */

.colophon {
  margin-top: var(--sp-8);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--ap-hairline);
  font-size: 12px;
  line-height: 1.6;
  color: var(--ap-ink-2);
}

.colophon p {
  margin: 0 0 var(--sp-1);
  max-width: none;
}

/* --- Utility -------------------------------------------------------------- */

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

/* Windows High Contrast Mode discards our colours entirely. Borders survive
 * where backgrounds do not, so every control here is defined by a border and
 * remains operable when the palette is gone. */
@media (forced-colors: active) {
  .btn,
  .license,
  input,
  select,
  textarea {
    border: 2px solid;
  }
  .band,
  .band-motto {
    forced-color-adjust: none;
  }
}
