/*
 * The sheet the screens that link no sheet of their own are drawn by.
 *
 * WHAT WAS MISSING, AND HOW LONG IT HAD BEEN MISSING
 *
 * Seventeen templates extend `templates/core/layout.tpl` and add nothing to it:
 * the six authentication screens, the four password screens, the home page, the
 * two account screens, the security screen, the invitation screen and both
 * installation screens. The layout linked the palette and the two utilities the
 * layout's own elements need, and neither of those carries a component or a
 * layout rule -- deliberately, and it is written in the token sheet's first
 * paragraph. So every one of those seventeen screens rendered in the engine's
 * default serif on the engine's default white, and every `a360-` class they
 * emit was named by a template and declared by nothing.
 *
 * No sheet for them was ever written and later lost. There is nothing to
 * restore here; this is the first one.
 *
 * WHY IT IS LINKED FROM THE LAYOUT AND NOT FROM A SCREEN
 *
 * A screen could link it, and the sign-in is the obvious place. That is refused
 * by a proof, and the property the proof holds is worth keeping: each of these
 * pages links exactly as many stylesheets as the layout does, which is one
 * count against another and says "this page adds nothing of its own". A link in
 * the sign-in raises one of the two counts and the page is reported. A link in
 * the layout raises both and the property still holds -- for the sixteen
 * screens nobody opened as much as for the one somebody did, which is the half
 * that matters, because nothing else in this repository enumerates them.
 *
 * WHAT THAT MEANS FOR EVERY OTHER SURFACE, WHICH ALSO GET THIS SHEET
 *
 * The layout is the whole product's layout. The administration shell, the
 * console, the operator workspace and the visitor window all extend it, so all
 * of them load this file whether they want it or not. Two things follow, and
 * both are decisions rather than side effects.
 *
 * Every one of those surfaces links its own sheet from inside the content
 * block, which is in the body and therefore after this one. Where they and this
 * file both have an opinion, theirs is the later rule and theirs wins. This
 * sheet is written to be overridden.
 *
 * And it is written narrow. There is no rule here for `input`, `button`,
 * `label`, `select` or `textarea` as elements, because the operator and visitor
 * templates between them carry sixty-five buttons and forty inputs whose
 * appearance belongs to sheets this file has no business repainting -- a border
 * and a fill applied from here would land on every icon-only control in the
 * console footer bar, and it would land there without anybody having looked at
 * it. The controls this file draws are the ones inside a form it can name.
 *
 * The three rules that are deliberately product-wide are `body`, the headings
 * and the footer. The first two give the product its typeface on surfaces that
 * had none -- the console and the visitor window declare no `body` rule at all,
 * which is why the licence line at the foot of both renders in a serif nothing
 * chose. The footer rule is that same defect's other half: the source offer is
 * emitted by the shared layout, so it is one defect on three surfaces and not
 * three defects, and it is repaired once, here.
 *
 * WHY THE PAGE IS `--surface` AND NOT `--ground`
 *
 * The administration puts its panels on `--surface` and the page behind them on
 * `--ground`, and its own sheet says why: `--link` and `--accent-text` are
 * legible on white and on nothing else the palette offers. That arrangement
 * needs a panel, and seven of these seventeen screens name no class at all --
 * the home page, both account screens, the security screen, the invitation
 * screen and two of the password screens. Their content sits directly on the
 * page, and three of them put a link there.
 *
 * On `--ground` that link measures 4.04 and owes 4.50. So the page itself is
 * `--surface`, every text colour this interface has is legible anywhere on it,
 * and the screens that name nothing are covered by the same argument as the
 * screens that name something. `--surface-alt` is used for the two bands that
 * carry no link -- a table head and the block of enrolment parameters -- where
 * `--text` measures 7.43 and `--heading` 13.01.
 *
 * WHY THE FIELD WRAPPER HAS NO RULE OF ITS OWN
 *
 * `a360-field` is emitted by eight of these templates and is also declared in
 * `public/assets/admin/kit.css`, and a proof beside that file holds every kit
 * class name to being defined by the kit and by no other sheet. That proof is
 * right: the administration loads this file too, so a second `.a360-field`
 * here would silently change the field spacing on every administration screen
 * from a sheet no administration screen names.
 *
 * The wrapper therefore carries no appearance, and its label and its control
 * carry theirs. That is where the appearance belongs in any case -- the wrapper
 * is a grouping element with nothing of its own to say -- and it means the two
 * surfaces can share a class name without sharing a rule. The proof beside this
 * file records the exception by name and asserts the kit still defines the
 * class, so the day the kit stops, the exception fails instead of outliving its
 * reason.
 *
 * WHAT THIS SHEET DOES NOT DO
 *
 * The account, security and invitation screens name no class on any control, so
 * their fields keep the platform's own. That is not an oversight and it is not
 * harmless-by-luck: a native control is the one every engine already draws
 * accessibly, and the alternative was a bare element rule reaching four other
 * surfaces. Giving those three templates a class is a change to those
 * templates, and they are not this file's to change.
 *
 * SPDX-License-Identifier: AGPL-3.0-only
 * Copyright (C) 2026 Astral Internet inc.
 */

/* ---- The page ------------------------------------------------------- */

/*
 * The typeface, the size and the two colours, stated once for every surface
 * this layout renders. `--text` on `--surface` measures 8.45.
 *
 * The margin is removed here rather than in each screen because the footer is
 * drawn edge to edge and a body margin would leave a white gutter around it
 * that no rule below could reach.
 */
body {
    background: var(--surface);
    color: var(--text);
    font-family: var(--font-text);
    font-size: var(--size-base);
    margin: 0;
}

/*
 * Headings, on all four surfaces, because a heading with no family declared is
 * a heading in the engine's serif and there is no sheet in this product that
 * declares one for the console or the visitor window.
 *
 * Colour and family only, plus the space around them. Nothing here decides how
 * big a heading is except the two sizes the palette already measured, so a
 * surface that wants its own scale sets it and this rule gets out of the way.
 */
h1,
h2,
h3 {
    color: var(--heading);
    font-family: var(--font-heading);
    font-weight: var(--font-heading-weight);
    margin-block: var(--core-gap-wide) var(--core-gap);
}

h1 {
    font-size: var(--size-visitor-title);
}

h2 {
    font-size: var(--size-subtitle);
}

h3 {
    font-size: var(--size-message-title);
}

/*
 * The prose the layout wraps. Held to a width a reader crosses without losing
 * the line, and left at the engine's own paragraph spacing, which is the one
 * thing about a paragraph that no screen here has ever needed to argue with.
 */
main p,
main li {
    max-inline-size: var(--core-prose-width);
}

/* ---- The source offer, which is drawn on every surface there is ------ */

/*
 * The AGPL offer the layout emits below the content. It rendered outside every
 * styled region on the sign-in, in the visitor window and in the console, in
 * the default serif, and it was one defect rather than three because one
 * template emits it.
 *
 * `--surface`, not `--surface-alt`, and the reason is the link inside it:
 * `--link` measures 4.52 on white and 3.98 on the alternate surface, so the
 * band that carries the offer has to be the white one. The hairline above is
 * what separates it from the content instead.
 */
.a360-footer {
    background: var(--surface);
    border-block-start: var(--core-rule) solid var(--border);
    color: var(--text);
    font-family: var(--font-text);
    font-size: var(--size-base);
    margin-block-start: var(--core-gap-wide);
    padding: var(--core-gap) var(--core-gap-wide);
}

.a360-footer p {
    margin: 0;
}

.a360-footer a {
    background: var(--surface);
    color: var(--link);
}

/* ---- The forms these screens are ------------------------------------ */

/*
 * Eight of the seventeen screens are a form and little else, and each names
 * itself. They are listed rather than reached through a shared class because
 * the templates name no shared class -- and adding one is a change to eight
 * templates this file does not own, which would be a change nothing here could
 * prove had been made everywhere.
 *
 * A panel on the same colour as the page, bounded by a hairline. `--border` is
 * decoration here and owes no ratio: the edge that identifies a control is the
 * control's own, and that one is `--control-edge` below.
 */
.a360-sign-in,
.a360-verify,
.a360-recovery,
.a360-enrol,
.a360-disenrol,
.a360-forgot,
.a360-reset {
    background: var(--surface);
    border: var(--core-rule) solid var(--border);
    color: var(--text);
    margin-block: var(--core-gap-wide);
    max-inline-size: var(--core-form-width);
    padding: var(--core-gap-wide);
}

/*
 * The installation form is the one that is wider, and it is wider for a reason
 * a reader can see: it holds a textarea sixty columns across, and a panel
 * narrower than its own control is a panel with a scroll bar in it.
 */
.a360-install {
    background: var(--surface);
    color: var(--text);
    margin-block: var(--core-gap-wide);
    max-inline-size: var(--core-page-width);
}

/*
 * The label of a field, above its control rather than beside it. Above is what
 * survives a narrow viewport without a media query, and this product's one
 * container query is in the console.
 *
 * `--heading` on the panel's `--surface` measures 14.81.
 */
.a360-sign-in label,
.a360-verify label,
.a360-recovery label,
.a360-enrol label,
.a360-disenrol label,
.a360-forgot label,
.a360-reset label,
.a360-install label {
    color: var(--heading);
    display: block;
    font-weight: var(--font-heading-weight);
    margin-block-end: var(--core-gap-tight);
}

/*
 * The control itself.
 *
 * Sixteen pixels, for the reason the administration's kit gives for the same
 * number: under sixteen a handheld browser zooms the page when the caret enters
 * the field and does not zoom back out, so every control after it is off the
 * side of the screen. This is the sign-in, so the field it happens on first is
 * the password field.
 *
 * `--control-edge` and not `--border`. The fill of an unfilled control is the
 * page's own colour, so its edge is the whole of what says a control is there,
 * and that edge is held to three to one. `--border` measures 1.28 against
 * white; this one measures 3.45.
 *
 * The box is bordered rather than content-sized because the inline size is a
 * hundred per cent and the padding is not nothing, and the two together in a
 * content box are a field wider than the panel around it.
 */
.a360-sign-in input,
.a360-verify input,
.a360-recovery input,
.a360-enrol input,
.a360-disenrol input,
.a360-forgot input,
.a360-reset input,
.a360-install input,
.a360-install textarea {
    background: var(--surface);
    border: var(--core-rule) solid var(--control-edge);
    box-sizing: border-box;
    color: var(--text);
    font-family: var(--font-text);
    font-size: var(--size-form);
    inline-size: 100%;
    margin-block-end: var(--core-gap-wide);
    min-block-size: var(--target-size);
    padding: var(--core-gap-tight);
}

/*
 * One ring for everything on these screens that can hold the keyboard, stated
 * once. `--brand-edge` measures 4.50 against the surface it is drawn on, and
 * with a positive offset the surface it is drawn on is the panel behind the
 * control rather than the control's own fill.
 *
 * Nothing in this file removes an outline, so nothing here has to put one back.
 */
.a360-sign-in input:focus-visible,
.a360-verify input:focus-visible,
.a360-recovery input:focus-visible,
.a360-enrol input:focus-visible,
.a360-disenrol input:focus-visible,
.a360-forgot input:focus-visible,
.a360-reset input:focus-visible,
.a360-install input:focus-visible,
.a360-install textarea:focus-visible,
.a360-submit:focus-visible {
    outline: var(--focus-ring-width) solid var(--brand-edge);
    outline-offset: var(--focus-ring-offset);
}

/*
 * The one field on the sign-in that is a choice rather than an answer. The box
 * comes before its label and neither is full width, so both of the rules above
 * are undone here rather than qualified there -- a control that is sometimes a
 * hundred per cent wide is how a checkbox ends up spanning a form.
 *
 * Never pre-checked, which is the template's decision and is written down
 * there; the appearance only has to make the two parts read as one control.
 */
.a360-field--choice {
    align-items: center;
    display: flex;
    gap: var(--core-gap-tight);
    margin-block-end: var(--core-gap-wide);
}

.a360-field--choice input {
    inline-size: auto;
    margin-block-end: 0;
    min-block-size: var(--target-size);
    min-inline-size: var(--target-size);
}

.a360-field--choice label {
    font-weight: normal;
    margin-block-end: 0;
}

/*
 * The sentence under a field that says what the field is for, and the sentence
 * under it that says what is wrong with the answer.
 *
 * The hint is smaller and the message is not: a message a reader has to be told
 * about is not a message to set in the smallest size on the page. The message
 * is `--accent-text-hover` on `--surface` at 5.66, and it is bold as well as
 * coloured, because a reader who cannot separate the two hues gets the same
 * information from the weight.
 */
.a360-field__hint {
    color: var(--text);
    display: block;
    font-size: var(--size-timestamp);
    margin-block: 0 var(--core-gap-wide);
}

.a360-field__message {
    background: var(--surface);
    color: var(--accent-text-hover);
    display: block;
    font-weight: var(--font-heading-weight);
    margin-block: 0 var(--core-gap-wide);
}

/*
 * The three states an installation field can arrive in. The severity is written
 * into the class by the installation controller from the same three constants
 * the requirement table uses, so the domain here is that domain and not a
 * longer one somebody guessed at.
 *
 * The passing state is drawn by nothing. A form in which every field is painted
 * green is a form in which the two fields that are not have to compete with
 * fifteen that are, and the state a reader is looking for is the exception.
 */
.a360-field--ok {
    border-inline-start: var(--core-rule-thick) solid transparent;
    padding-inline-start: var(--core-gap);
}

.a360-field--warn {
    border-inline-start: var(--core-rule-thick) solid var(--msg-alert-text);
    padding-inline-start: var(--core-gap);
}

.a360-field--fail {
    border-inline-start: var(--core-rule-thick) solid var(--brand-edge);
    padding-inline-start: var(--core-gap);
}

/* ---- The one button these screens have ------------------------------ */

/*
 * The border is what identifies the control, at 4.50 against the panel. That is
 * the whole reason the fill may keep the brand colour: the fill is not carrying
 * the requirement. The label is `--on-brand` at 4.87, and white on this fill
 * would be 3.04 -- which is what the interface being replaced used, on every
 * primary button it had.
 */
.a360-submit {
    background: var(--brand-fill);
    border: var(--core-rule) solid var(--brand-edge);
    color: var(--on-brand);
    cursor: pointer;
    font-family: var(--font-text);
    font-size: var(--size-base);
    font-weight: var(--font-heading-weight);
    min-block-size: var(--target-size);
    min-inline-size: var(--target-size);
    padding: var(--core-gap-tight) var(--core-gap-wide);
}

.a360-submit:hover {
    background: var(--brand-fill-hover);
    color: var(--on-brand);
}

/*
 * Refused rather than hidden. The installation form disables its submit when a
 * requirement failed, and a control that is disabled and looks exactly like one
 * that is not is a control somebody presses repeatedly.
 *
 * `--tab-idle-text` on `--surface-alt` measures 4.54, so the label of a refused
 * button is still readable -- it says what pressing it would have done, and a
 * reader has to be able to find out what they are being refused.
 */
.a360-submit[disabled] {
    background: var(--surface-alt);
    border-color: var(--tab-idle-border);
    color: var(--tab-idle-text);
    cursor: default;
}

/* ---- What a screen says before its form ----------------------------- */

/*
 * The one refusal, drawn in one place. Which of the three things went wrong is
 * not on the sign-in and must not become visible there later, so this is one
 * appearance for one sentence rather than a set of tones a screen chooses from.
 *
 * `--msg-alert-text` on `--msg-alert-bg` measures 4.88. The rule at the start
 * is what carries the meaning for a reader who separates no hues at all.
 */
.a360-notice {
    background: var(--msg-alert-bg);
    border-inline-start: var(--core-rule-thick) solid var(--msg-alert-text);
    color: var(--msg-alert-text);
    margin-block: var(--core-gap-wide);
    max-inline-size: var(--core-form-width);
    padding: var(--core-gap) var(--core-gap-wide);
}

/*
 * The sentence that says something is about to become impossible to undo --
 * the recovery codes shown once, the second factor about to be given up.
 *
 * It is deliberately not the notice above, because the disenrolment screen
 * carries both at once and two identical bands are two sentences a reader reads
 * as one. `--accent-text` on `--surface` measures 4.50, and it is bold, so the
 * difference between the two survives a reader who sees neither colour.
 */
.a360-warning {
    background: var(--surface);
    border-inline-start: var(--core-rule-thick) solid var(--brand-edge);
    color: var(--accent-text);
    font-weight: var(--font-heading-weight);
    margin-block: var(--core-gap-wide);
    max-inline-size: var(--core-form-width);
    padding: var(--core-gap) var(--core-gap-wide);
}

/* ---- Enrolment, which is a secret shown two ways --------------------- */

/*
 * The symbol a phone reads. Centred and no wider than the panel, and its
 * drawing is allowed to grow with the container rather than being pinned to the
 * scale the encoder happened to use -- a fixed size here is a symbol that is
 * either too small to scan on a handheld or wider than the screen.
 *
 * The caption is not decoration. It is the sentence that tells somebody whose
 * camera cannot see the drawing that there is another way, and the other way is
 * the block below.
 */
.a360-enrol__symbol {
    margin: var(--core-gap-wide) 0;
    text-align: center;
}

.a360-enrol__symbol svg {
    block-size: auto;
    max-inline-size: 100%;
}

.a360-enrol__symbol figcaption {
    color: var(--text);
    font-size: var(--size-timestamp);
    margin-block-start: var(--core-gap-tight);
}

/*
 * The same secret, for somebody typing it in. A band rather than a panel,
 * because it is an alternative to the drawing above and not a second step.
 *
 * `--surface-alt` carries no link on this screen, which is what allows it to be
 * used at all: `--text` measures 7.43 there and `--heading` 13.01, and both are
 * the only two colours inside it.
 */
.a360-enrol__manual {
    background: var(--surface-alt);
    color: var(--text);
    margin-block: var(--core-gap-wide);
    max-inline-size: var(--core-form-width);
    padding: var(--core-gap-wide);
}

/*
 * The parameters, as a list of terms and their values. Two columns where there
 * is room for two and one column where there is not, without a media query --
 * the grid is asked for a track that fits its content and a track that takes
 * what is left, and a narrow viewport wraps it.
 */
.a360-enrol__parameters {
    display: grid;
    gap: var(--core-gap-tight) var(--core-gap-wide);
    grid-template-columns: max-content 1fr;
    margin: 0;
}

.a360-enrol__parameters dt {
    color: var(--heading);
    font-weight: var(--font-heading-weight);
}

.a360-enrol__parameters dd {
    margin: 0;
}

/*
 * The secret itself. Monospaced, because it is transcribed rather than read,
 * and allowed to wrap at the spaces the policy already grouped it by -- the
 * grouping is the policy's and this rule keeps it rather than re-flowing it.
 */
.a360-enrol__secret {
    background: var(--surface);
    color: var(--heading);
    font-family: monospace;
    font-size: var(--size-form);
    letter-spacing: 0.05em;
}

/*
 * How many attempts are left. It sits between the field and the button, where
 * somebody who has just been refused is looking.
 */
.a360-enrol__remaining {
    color: var(--text);
    font-size: var(--size-timestamp);
    margin-block: 0 var(--core-gap);
}

/*
 * The recovery codes, at the one moment they are visible. Laid out in columns
 * that fit rather than in a number of columns chosen here, so the list is as
 * wide as the screen allows and no wider.
 *
 * The ordinal is kept. These are transcribed under time pressure by somebody
 * who has just turned on a second factor, and a numbered list is how a person
 * finds their place again after looking away.
 */
.a360-enrolled__codes {
    display: grid;
    gap: var(--core-gap-tight) var(--core-gap-wide);
    grid-template-columns: repeat(auto-fill, minmax(var(--core-code-width), 1fr));
    margin-block: var(--core-gap-wide);
    max-inline-size: var(--core-page-width);
    padding-inline-start: var(--core-ordinal-width);
}

.a360-enrolled__codes code {
    background: var(--surface);
    color: var(--heading);
    font-family: monospace;
    font-size: var(--size-form);
}

.a360-enrolled__count {
    color: var(--text);
    font-weight: var(--font-heading-weight);
    margin-block: var(--core-gap-wide) var(--core-gap);
}

/* ---- The installation, which is the first screen anybody sees -------- */

/*
 * A group of settings that answer one question together. It is a fieldset in
 * the markup because that is the element whose legend an engine announces
 * before each control inside it, and the border here is what makes the grouping
 * visible to everybody who is not listening to it.
 */
.a360-section {
    border: var(--core-rule) solid var(--border);
    margin-block-end: var(--core-gap-wide);
    padding: var(--core-gap-wide);
}

.a360-section > legend {
    color: var(--heading);
    font-family: var(--font-heading);
    font-weight: var(--font-heading-weight);
    padding-inline: var(--core-gap-tight);
}

/*
 * The requirement table. Collapsed, so the hairline between two rows is one
 * hairline, and full width because the third column holds a sentence.
 */
.a360-checks {
    border: var(--core-rule) solid var(--border);
    border-collapse: collapse;
    inline-size: 100%;
    margin-block: var(--core-gap-wide);
    max-inline-size: var(--core-page-width);
}

.a360-checks thead {
    background: var(--surface-alt);
    color: var(--heading);
}

.a360-checks th,
.a360-checks td {
    border-block-end: var(--core-rule) solid var(--border);
    padding: var(--core-gap-tight) var(--core-gap);
    text-align: start;
    vertical-align: top;
}

/*
 * A row of the table, and the three states one can be in. The severity is the
 * same closed set the fields use, written into the class by the controller.
 *
 * The failing row is not a red fill, and the reason is the palette rather than
 * taste: nothing measured here carries a red that text is legible on, so a red
 * row would be a colour invented for one state -- which is how a second palette
 * begins, and the palette check would not see it, because the value would be in
 * a component sheet rather than in the token list. The weight is carried by the
 * rule at the start of the row and by the colour of its text, at 4.50.
 */
.a360-check {
    background: var(--surface);
    color: var(--text);
}

.a360-check--ok {
    background: var(--msg-notice-bg);
    color: var(--msg-notice-text);
}

.a360-check--warn {
    background: var(--msg-alert-bg);
    color: var(--msg-alert-text);
}

.a360-check--fail {
    background: var(--surface);
    color: var(--accent-text);
    font-weight: var(--font-heading-weight);
}

/*
 * The status word and the detail beside it. The status is the answer and the
 * detail is the evidence, so the first does not wrap and the second may.
 */
.a360-check__status {
    font-weight: var(--font-heading-weight);
    white-space: nowrap;
}

.a360-check__detail {
    font-size: var(--size-timestamp);
}

/*
 * The sentence above a submit button that cannot be pressed. It says why, and
 * it is drawn in the same colour as the failing rows above it, so the reader
 * who has just read one recognises the other.
 */
.a360-blocked {
    background: var(--surface);
    color: var(--accent-text);
    font-weight: var(--font-heading-weight);
    margin-block: var(--core-gap-wide) var(--core-gap);
    max-inline-size: var(--core-page-width);
}

/*
 * What the installation refused, and what it finished without. Two lists on two
 * screens, and one appearance, because they are the same sentence at two
 * moments -- something the installation could not do, named, with the reason
 * beside it.
 */
.a360-refused,
.a360-incomplete {
    background: var(--msg-alert-bg);
    border-inline-start: var(--core-rule-thick) solid var(--msg-alert-text);
    color: var(--msg-alert-text);
    margin-block: var(--core-gap-wide);
    max-inline-size: var(--core-page-width);
    padding: var(--core-gap) var(--core-gap-wide);
}

/*
 * The three lists the finished installation leaves behind: where to sign in,
 * what still has to be done by hand, and which migrations ran. The first two
 * are read and acted on; the third is a record, so it is the quiet one.
 */
.a360-links {
    margin-block: var(--core-gap-wide);
    padding-inline-start: var(--core-gap-wide);
}

.a360-links a {
    background: var(--surface);
    color: var(--link);
}

.a360-steps {
    margin-block: var(--core-gap-wide);
    max-inline-size: var(--core-prose-width);
    padding-inline-start: var(--core-gap-wide);
}

.a360-steps li {
    margin-block-end: var(--core-gap);
}

.a360-applied {
    color: var(--text);
    font-family: monospace;
    font-size: var(--size-timestamp);
    margin-block: var(--core-gap);
    padding-inline-start: var(--core-gap-wide);
}

/* ---- Lengths this file needs and the token sheet should not carry ---- */

/*
 * Spacing, rule weights and the four widths below are this sheet's own. They
 * are declared here rather than in the token sheet for the reason the
 * administration's kit gives for the same decision: the token sheet holds the
 * measured identity, a check compares every value in it against the appearance
 * document, and a spacing step invented for a sign-in is not one of those.
 *
 * The steps are the kit's steps and the same four numbers, because two sheets
 * in one product that space things four and eight and sixteen apart, but
 * disagree about which is which, are two sheets nobody can move a rule between.
 */
:root {
    --core-gap-tight: 4px;
    --core-gap: 8px;
    --core-gap-wide: 16px;

    --core-rule: 1px;
    --core-rule-thick: 3px;

    /* Wide enough for a warning, narrow enough to read in one pass. */
    --core-prose-width: 60ch;

    /* A form that is only ever one column does not need to be wider. */
    --core-form-width: 32rem;

    /* The installation holds a textarea sixty columns across. */
    --core-page-width: 48rem;

    /* A recovery code and the space between two of them. */
    --core-code-width: 14ch;

    /* Two digits and the space a third would need. */
    --core-ordinal-width: 3ch;
}
