/*
 * Novo Nordisk Step Count — application styles.
 *
 * Every value here comes from public/css/tokens.css. No brand value is written directly:
 * the design contract makes the token layer the single implementation source, so a brand
 * change stays a change to one file (docs/design/novo-nordisk-design-contract.md).
 *
 * Mobile-first. Every media query is min-width, so the phone layout is the base case and
 * wider viewports enhance it — the employee entering steps is on a phone.
 *
 * Deliberately small. [NOVO] "Any element that does not serve a purpose should be removed",
 * which is also the product's first principle.
 */

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

html {
    /* Never disable user scaling, and never set a fixed root size: the type scale is in
     * rem so it follows the reader's own browser setting. */
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--colour-surface);
    color: var(--colour-text);
    font-family: var(--font-family-base);
    font-size: var(--font-size-base);
    line-height: var(--line-height-base);
}

/* --- Skip link ---------------------------------------------------------------------------
 * WCAG 2.2 AA, 2.4.1 Bypass Blocks. Hidden until focused, then unmissable.
 */
.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 1;
    padding: var(--space-xs) var(--space-sm);
    background: var(--colour-surface);
    color: var(--colour-primary);
    font-weight: var(--font-weight-medium);
}

.skip-link:focus {
    left: 0;
}

/* --- Links -------------------------------------------------------------------------------
 * A base rule, because the alternative is not "no style" — it is the user agent's #0000EE,
 * which is not one of the eleven official Novo colours. A brand value can drift into the
 * product by omission as easily as by a hard-coded hex, and this is the only place that can
 * happen. The underline is kept: it is what carries the link independently of colour
 * (WCAG 2.2 AA, 1.4.1), and :focus-visible below already covers the focused state.
 */
a {
    color: var(--colour-primary);
}

/* --- `hidden` MEANS HIDDEN ------------------------------------------------------------------
 *
 * THE BROWSER'S OWN `[hidden] { display: none }` IS A USER-AGENT DECLARATION, and any author
 * `display` beats it whatever its specificity and wherever it sits. So every component in this
 * file that sets `display` — which is most of them — silently cancels the attribute for its own
 * elements. Found on the team screen's Copy link button: it is rendered with `hidden` and
 * un-hidden by script once the clipboard has been found, and with the script blocked it drew at
 * 358×52 and sat in the tab order, offering to copy and doing nothing. The markup was right and
 * the stylesheet was quietly overruling it.
 *
 * `!important` because that is the only thing that outranks a later author declaration, and
 * because there is no case in this product where an element carrying `hidden` should be drawn.
 * It is the whole point of the attribute: one place, so no component has to remember.
 */
[hidden] {
    display: none !important;
}

/* --- Focus -------------------------------------------------------------------------------
 * One rule, applied everywhere, never removed. An outline that is only visible on some
 * controls is the same defect as no outline at all.
 */
:focus-visible {
    outline: var(--focus-ring-width) solid var(--colour-focus);
    outline-offset: var(--focus-ring-offset);
}

/* --- Layout ------------------------------------------------------------------------------
 * [NOVO] "Use a lot of white space to create a calm and clear design."
 */
.page {
    max-width: var(--layout-measure);
    margin: 0 auto;
    padding: var(--space-lg) var(--layout-gutter) var(--space-2xl);
}

.page__header {
    margin-bottom: var(--space-lg);
}

h1 {
    margin: 0 0 var(--space-2xs);
    font-size: var(--font-size-2xl);
    line-height: var(--line-height-tight);
    font-weight: var(--font-weight-bold);
}

.lede {
    margin: 0;
    color: var(--colour-text-muted);
}

@media (min-width: 40rem) {
    .page {
        padding-top: var(--space-xl);
    }

    h1 {
        font-size: var(--font-size-3xl);
    }
}

/* --- Status message ----------------------------------------------------------------------
 * A notice: a confirmation, a fact, a reason or a refusal. Meaning is carried by the words, never
 * by colour alone (WCAG 2.2 AA, 1.4.1) — which matters doubly with this palette, where most brand
 * colours cannot reach 4.5:1 on white. Its v4 shape and mark: "THE NOTICES IN v4" at the end.
 */
.status {
    margin: 0 0 var(--space-md);
    padding: var(--space-xs) var(--space-sm);
    border-left: var(--border-width-strong) solid var(--colour-success);
    background: var(--colour-surface-sunken);
    color: var(--colour-status-text);
}

/* A state that is neither a success nor a failure: "nothing is configured yet".
 *
 * The plain .status carries a Forest Green accent because it was written for a confirmation
 * after a save. Reusing it for a persistent, neutral fact reads as "something just succeeded"
 * to somebody scanning — design review caught the collision. The wording carries the meaning
 * either way (WCAG 2.2 AA, 1.4.1); this stops the colour arguing with it.
 */
.status--info {
    border-left-color: var(--colour-info);
}

/* Neither a success nor a failure: a reason the operator must act on before something can
 * happen. Golden Yellow is an accent only at 2.03:1, so — like .status--error — the width
 * carries the difference for anyone who cannot rely on hue, and the wording carries it
 * regardless (WCAG 2.2 AA, 1.4.1). */
.status--warning {
    border-left-width: var(--border-width-accent);
    border-left-color: var(--colour-warning);
}

.status--error {
    /* Wider as well as red. The accent measures about 3:1 against the sunken fill it sits
     * on, so hue alone is thin; width carries the difference for anyone who cannot rely on
     * it, and the wording carries it regardless (WCAG 2.2 AA, 1.4.1). */
    border-left-width: var(--border-width-accent);
    border-left-color: var(--colour-danger);
}

.status__title {
    margin: 0;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
}

/* The error summary is a link to the field that was refused. Underlined rather than coloured:
 * the surrounding text is already --colour-status-text, so hue would carry nothing, and an
 * underline is the one link affordance that does not depend on it (WCAG 2.2 AA, 1.4.1). */
.status__link {
    color: inherit;
}

/* --- Step entry field --------------------------------------------------------------------
 * Shared by every editable campaign day. No fieldset: a group wrapper round a single control
 * makes assistive technology announce a group name that adds nothing over the label.
 */
.field__error {
    display: block;
    margin-bottom: var(--space-2xs);
    font-weight: var(--font-weight-medium);
    /* True Blue, not Lava Red: Lava Red is 3.66:1 on white and fails AA for text. The red
     * carries on the border below, where 3:1 is the applicable threshold. */
    color: var(--colour-status-text);
}

/*
 * THE PLACEHOLDER COLOUR IS DECLARED, NOT LEFT TO THE BROWSER.
 *
 * The landing hero is the only field in this product carrying a placeholder, and when its
 * bespoke input rules were deleted in favour of this class the ::placeholder rule went with
 * them — so the front door's one field rendered its hint in the user agent's own grey, which
 * is not one of the eleven official values and differs between engines. This project treats a
 * UA colour arriving by omission as a defect everywhere else; here it arrived by deletion.
 */
.field__input::placeholder {
    color: var(--colour-text-muted);
    opacity: 1;
}

.field__input {
    display: block;
    width: 100%;
    min-height: var(--touch-target-min);
    padding: var(--space-2xs) var(--space-xs);
    border: var(--border-width-strong) solid var(--colour-border-strong);
    border-radius: var(--radius-md);
    background: var(--colour-surface);
    color: var(--colour-text);
    font-family: inherit;
    /* 1rem minimum: iOS Safari zooms the viewport when a focused input is below 16px. */
    font-size: var(--font-size-lg);
}

.field__input[aria-invalid='true'] {
    border-color: var(--colour-danger);
    /* A refused save lands on the field by its fragment; the label and the error sit above it,
     * so the page stops short of the field's top edge and all three are in view. The error wraps
     * on a phone: label and error measure 107px above the field at 390 and 156px at 320. */
    scroll-margin-top: 12rem;
}

/* --- Button ------------------------------------------------------------------------------ */
.button {
    /* NO LINK UNDERLINE. This class is worn by <a> as often as by <button> — the team screen's
     * onward action, the expired-link recovery, the diploma, the public bar's call to action —
     * and the user agent's underline showed through on every one of them, so a filled True
     * Blue button also read as a link. Declared here rather than on each anchor. */
    text-decoration: none;
    display: inline-block;
    width: 100%;
    min-height: var(--touch-target-min);
    padding: var(--space-2xs) var(--space-md);
    border: var(--border-width-strong) solid var(--colour-primary);
    border-radius: var(--radius-md);
    background: var(--colour-primary);
    color: var(--colour-text-on-primary);
    font-family: inherit;
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-medium);
    line-height: var(--line-height-tight);
    text-align: center;
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--easing-standard);
}

.button:hover {
    background: var(--colour-primary-hover);
    border-color: var(--colour-primary-hover);
}

@media (min-width: 40rem) {
    .button {
        width: auto;
        min-width: 12rem;
    }
}

/* --- Available to assistive technology, absent from the page -------------------------------
 * Used where the visible text is an abbreviation the eye needs and the ear does not — "Sat 22"
 * against "Saturday 22 August 2026". The clip-path/1px pairing is the form that survives being
 * inside a flex container without collapsing the row it sits in.
 *
 * GLOBAL, and it lives here rather than beside the screen that first wanted it. It was inside
 * the campaign section, and rewriting that screen took it out with the rest — which showed up
 * as every hidden label in the product suddenly rendering, on pages that had nothing to do with
 * the change.
 */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* --- Notices -----------------------------------------------------------------------------
 * Campaign state: "not started yet", "the campaign has ended". Quiet by construction —
 * neither is a problem the participant has caused, so neither gets the visual weight of an
 * error.
 *
 * The .notice--quiet variant went with the assumed-timezone line it was written for. Nothing
 * announces an assumption any more, because onboarding makes the fallback unreachable.
 */
.notice {
    margin: 0 0 var(--space-md);
    padding: var(--space-xs) var(--space-sm);
    border-left: var(--border-width-strong) solid var(--colour-border-strong);
    background: var(--colour-surface-sunken);
    color: var(--colour-text);
}

/* --- The gate ---------------------------------------------------------------------------------
 * Sign in, check your email, confirm, onboarding, create a team.
 *
 * Every one of these screens is one question and one button. They share a container that is
 * narrower than the campaign's measure and vertically centred on tall viewports, because a
 * single short form stranded at the top of a 900px screen reads as an error state rather than
 * as an invitation. [NOVO] carries layout with whitespace, and this is the screen with the
 * least to say and therefore the most whitespace to carry it.
 */
/*
 * THE GATE SCREENS ARE THE REST OF THE CAMPAIGN, and until now they did not look like it.
 *
 * The landing page is a True Blue campaign field. The first thing "Create your team" leads to
 * is this component, and it was an unstyled form on a white page - so the captain crossed from
 * a campaign into what reads as a different product, at exactly the moment they are deciding
 * whether to bother. Sign-in, check-your-email, onboarding and create-team all use this
 * component, so making it one thing makes the whole first run one thing.
 *
 * A raised card on the sunken tint, which is the same blue-tint-white rhythm the landing page
 * already establishes. No new colour, no new component, and the markup is untouched: every
 * screen using .gate inherits this without a single view changing.
 */
/*
 * The campaign's name above a gate card. Sized and spaced like the public bar's mark so the
 * two read as the same product, but quieter - it orients, it is not a heading, and the h1
 * below it is what the page is about.
 */
.gatemark {
    /*
     * TIGHTER ON A DATA SCREEN THAN ON A GATE. The wordmark was extended to every
     * authenticated screen so somebody opening a link from their inbox could tell what this
     * is — which is a gate-screen problem. On the step screen it sits above a two-row
     * navigation, and together they were taking about 250 of the first 664 CSS pixels before
     * the page title, on the screen the product exists for. It keeps its full breathing space
     * on the gate pages, where it is doing the work it was added for.
     */
    margin: 0 0 var(--space-sm);
    color: var(--colour-primary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    text-align: center;
}

.gate-page .gatemark {
    margin-bottom: var(--space-lg);
}

.gate {
    max-width: 26rem;
    margin: var(--space-lg) auto var(--space-2xl);
    padding: var(--space-lg);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-md);
    background: var(--colour-surface-raised);
    box-shadow: var(--shadow-md);
}

@media (min-width: 40em) {
    .gate {
        padding: var(--space-xl);
    }
}

/*
 * The tint goes on the page rather than the card, so the card has something to sit against.
 * Scoped to the body class the gate layouts already carry rather than applied globally, so
 * data screens keep their white ground - a tinted background behind a long table is noise.
 */
.gate-page {
    background: var(--colour-surface-sunken);
}

.gate--wide {
    /* Onboarding has two fields and a select whose option labels are long. */
    max-width: 32rem;
}

.gate__header {
    margin-bottom: var(--space-lg);
}

/*
 * The heading carries more weight here than on a data screen. This is the moment the product
 * asks somebody for something, and a 1.75rem heading above a form reads as a field group
 * label rather than as a question being asked.
 */
/* EXCEPT WHERE THE TITLE CLASS SAYS OTHERWISE. This descendant selector is (0,1,1) and
 * .support__heading is (0,1,0), so the admin identity screen — the one admin view wrapped in a
 * gate — silently kept the participant 3xl after being given the admin title class. The markup
 * said one thing and the cascade did another, which is worse than either alone. */
.gate__header h1:not(.support__heading, .decision__heading) {
    font-size: var(--font-size-3xl);
    line-height: var(--line-height-tight);
    text-wrap: balance;
}

.gate__header .lede {
    margin-top: var(--space-2xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-lg);
}

.gate__form {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
}

.gate__label {
    font-weight: var(--font-weight-medium);
}

.gate__hint {
    display: block;
    margin-bottom: var(--space-2xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* A HINT INSIDE A FORM TAKES ITS SPACING FROM THE FORM, NOT FROM ITS TAG.
 *
 * This class is worn by both <span> and <p> across the product, and only the <p> carries the
 * user agent's 1em top margin — so on the create-a-team screen "Anything your colleagues will
 * recognise" sat roughly three times further from its label than the identical hint does on
 * onboarding, which uses a <span>. Two screens one click apart in the first-run journey, the
 * same sentence, different spacing, and nothing in the markup or the class to suggest it.
 *
 * Scoped to the form deliberately. Several standalone <p class="gate__hint"> paragraphs on
 * other screens are currently separated from what precedes them BY that user-agent margin, and
 * removing it everywhere would silently re-space screens outside this journey. */
.gate__form .gate__hint {
    margin-top: 0;
}

.gate__input,
.gate__select {
    width: 100%;
}

.gate__select {
    /* A select inherits none of the input styling in any browser, so the shared token values
     * are restated rather than assumed. The height matches the touch-target minimum. */
    min-height: var(--touch-target-min);
    background: var(--colour-surface);
    color: var(--colour-text);
    font-size: var(--font-size-base);
}

.gate__submit {
    margin-top: var(--space-sm);
    width: 100%;
}

/* The address the visitor typed, returned to them. Bold rather than coloured: it is the one
 * thing on this page they need to check, and colour alone would not say so to everybody.
 *
 * THE LINE IS BODY SIZE, NOT LARGE. It carries a full conditional sentence now — the
 * anti-enumeration phrasing — and setting a sentence of that length at --font-size-lg made the
 * hedge shout while the address it is about stayed the same weight as everything around it. */
.gate__sent {
    margin: var(--space-xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-base);
    line-height: var(--line-height-base);
}

.gate__sent-address {
    color: var(--colour-text);
    /*
     * ANYWHERE, NOT BREAK-ALL — and the difference is the whole point of the element.
     *
     * break-all fills every line to its last character whether or not the word would fit on
     * the next one, so at 390px "jane.doe@example.test" rendered as "jane.doe@exampl / e.test":
     * the domain split mid-word on the one screen that exists so somebody can spot a typo.
     * overflow-wrap: anywhere breaks only when the address genuinely cannot fit, which keeps
     * the local part and the domain whole in every case that has room for them.
     */
    overflow-wrap: anywhere;
}

/* The body of a gate screen when it is telling rather than asking. Full-strength text at
 * reading size: this is the sentence the screen exists to deliver, not a caption under
 * something else. */
.gate__body {
    margin: var(--space-md) 0 0;
    color: var(--colour-text);
    font-size: var(--font-size-lg);
    line-height: var(--line-height-base);
}

.gate__alternate {
    margin-top: var(--space-md);
}

/* Each field is a group, so the gap in .gate__form does not collapse a label onto the input
 * above it when there is more than one. */
.field {
    display: flex;
    flex-direction: column;
    margin-bottom: var(--space-md);
}

/* STACKED FIRST, THEN A ROW — the same shape as a day's entry controls, because it is the
 * same shape of thing: a field and the button that submits it, inside an accent-spined panel.
 *
 * wrap alone was not equivalent. At 390px the field's 14rem basis pushed the button onto its
 * own line, where flex:0 0 auto kept it at its text width — so two panels one screen apart in
 * the same journey put their primary button at full width on one and at 255px on the other,
 * for no reason a reader could see. */
.invite__controls {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
    align-items: stretch;
}

/* THE BASIS BELONGS TO THE ROW, NOT TO THE FIELD. flex-basis is measured along the main axis,
 * so the field's 14rem followed the container into the column and became a 224px-TALL email
 * box on a phone. Rendered and looked at, which is the only reason this was caught: the rule
 * reads as a width everywhere it is written down. */
.invite__input {
    flex: 0 0 auto;
}

@media (min-width: 30rem) {
    .invite__controls {
        flex-direction: row;
    }

    .invite__input {
        flex: 1 1 14rem;
    }
}

.invite__submit {
    flex: 0 0 auto;
    width: auto;
}

/* --- A LINK THAT STANDS ALONE IN A CARD ------------------------------------------------------
 *
 * Every board draws these without an underline and in weight: "Send a reminder", "Delete",
 * "Invite again", "Gå til Mit hold", "Change where the team counts". They are actions sitting on
 * their own in a cell or at the foot of a card, where nothing else nearby is a link, so position
 * and weight already tell a reader what they are.
 *
 * AND LINKS INSIDE RUNNING TEXT KEEP THEIRS, which is why this is a separate rule and not a
 * blanket `a { text-decoration: none }`. A link in a sentence is surrounded by words that are not
 * links, so colour is the only thing distinguishing it — and colour alone is exactly what
 * WCAG 1.4.1 forbids as the sole carrier of meaning.
 *
 * A LINK IN RUNNING TEXT GETS THE BROWSER'S UNDERLINE, untouched: the base `a` rule sets colour
 * and nothing else, and only an anchor that opts into this rule loses the underline at rest.
 * Opting in, rather than writing `a { none }`, is what keeps a prose link underlined the day
 * somebody writes one.
 *
 * ONE RULE, NOT A PER-PAGE OVERRIDE (ACC-005 item 5). The treatment lives here once and the
 * components below opt into it; scattering `text-decoration: none` through five screens is how
 * the sixth one ends up different and nobody notices.
 *
 * EVERY STANDALONE ARROW LINK TAKES IT (Kenneth, 2026-09-27): "Se hvem →", "Gå til mail →",
 * "Invitér én kollega mere →", "Kampagneindstillinger →" and the like, participant and admin,
 * carry no underline at rest and show it on hover and keyboard focus. The arrow is the cue that
 * does not depend on colour (WCAG 1.4.1). A link inside running text keeps its underline. `a.`
 * so that a component's own link class (.text-link) cannot outrank it. */
a.link-standalone,
.link-button {
    text-decoration: none;
    font-weight: var(--font-weight-bold);
}

a.link-standalone:hover,
.link-button:hover,
a.link-standalone:focus-visible,
.link-button:focus-visible {
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

/* A submit button that reads as a link. Used for "send a new link", which is a small action
 * beside a name rather than a call to action — a second full-width button there would compete
 * with the invitation form above it. It stays a real <button> in a real <form>, so it is
 * keyboard operable and works with no JavaScript. */
.link-button {
    padding: var(--space-3xs) 0;
    border: 0;
    background: none;
    color: var(--colour-primary);
    font-family: inherit;
    font-size: var(--font-size-sm);
    cursor: pointer;
}

.link-button:hover {
    color: var(--colour-primary-hover);
}

/* --- Where the team belongs -------------------------------------------------------------------
 * A COMPACT SETTING, NOT AN INFORMATION PANEL. It had a circled icon, a full panel heading and a
 * paragraph of explanation for two selects the labels already describe. Design Guide v2 asks for
 * it "visually compact", which is what a captain changing one value once wants.
 */
.place-panel .panel__icon {
    display: none;
}

.place-panel .panel__title {
    font-size: var(--font-size-lg);
}

.place-panel .panel__head {
    margin-bottom: var(--space-2xs);
}

/* THE ROSTER ON A PHONE. The cells stack, so a name has the card's width and needs no breaking;
 * only a long address does, and it breaks at its own punctuation rather than mid-word. */
@media (max-width: 47.99rem) {
    .roster-table__name {
        width: auto;
    }

    .roster-table__person {
        word-break: normal;
        overflow-wrap: anywhere;
    }
}

/* --- The phone's menu ---------------------------------------------------------------------
 *
 * Design Guide v2: a STEP COUNT header and a menu button on a phone, never the desktop row
 * wrapped onto three lines.
 *
 * NO SCRIPT ANYWHERE NEAR IT. <details>/<summary> is the browser's own disclosure — it opens on
 * click and on Enter or Space, closes the same way, and is announced as expanded or collapsed.
 * A small enhancement script was written first and three existing guards refused it: these
 * screens assert they carry no scripting at all, which is what makes "works without JavaScript"
 * a fact rather than a hope.
 *
 * TWO NAVIGATIONS, ONE VISIBLE. The disclosure holds its own copy of the links and the row holds
 * the other; exactly one is displayed at any width and the other is display:none, so it is out of
 * the accessibility tree as well. Both render resources/views/partials/participant-links.blade.php,
 * so they cannot disagree about what exists. An element cannot be inside the disclosure and beside
 * it at the same time, and duplicating five links is cheaper than a script.
 */
.navmenu {
    margin-left: auto;
}

.navmenu__toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: var(--touch-target-min);
    min-height: var(--touch-target-min);
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-lg);
    background: var(--colour-surface);
    color: var(--colour-primary);
    cursor: pointer;
    list-style: none;
}

.navmenu__toggle::-webkit-details-marker {
    display: none;
}

.navmenu__toggle:focus-visible {
    outline: var(--focus-ring-width) solid var(--colour-focus);
    outline-offset: var(--focus-ring-offset);
}

/* Three rules, drawn from borders. Not an icon: the design contract forbids drawing one that
 * pretends to be Novo's, and three lines are a geometric primitive rather than a mark. */
.navtoggle__bars,
.navtoggle__bars::before,
.navtoggle__bars::after {
    display: block;
    width: 1.125rem;
    height: 2px;
    border-radius: 1px;
    background: currentColor;
}

.navtoggle__bars {
    position: relative;
}

.navtoggle__bars::before,
.navtoggle__bars::after {
    content: "";
    position: absolute;
    left: 0;
}

.navtoggle__bars::before {
    top: -0.35rem;
}

.navtoggle__bars::after {
    top: 0.35rem;
}

/* The opened panel: full-width rows at a thumb-sized target, which is what a phone menu is for. */
.navmenu__panel {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    width: 100%;
    margin-top: var(--space-xs);
    padding: var(--space-2xs) 0;
    border-top: var(--border-width) solid var(--colour-border-soft);
}

.navmenu__panel .bar__link {
    display: flex;
    align-items: center;
    min-height: var(--touch-target-min);
    padding: var(--space-2xs) 0;
}

.navmenu__person {
    margin: var(--space-2xs) 0 0;
    padding-top: var(--space-2xs);
    border-top: var(--border-width) solid var(--colour-border-soft);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.navmenu__out {
    margin: var(--space-3xs) 0 0;
}

@media (max-width: 63.99rem) {
    /* The phone shows the disclosure and hides the row, the person and the separate way out —
     * all three live inside the menu at this width. */
    .topbar .bar,
    .topbar .whoami,
    .topbar .bar__out {
        display: none;
    }
}

@media (min-width: 64rem) {
    /* The laptop shows the row and hides the disclosure; the phone does the opposite. */
    .navmenu {
        display: none;
    }
}

/* --- The bar ----------------------------------------------------------------------------------
 * The whole of this product's navigation, for a signed-in participant only. It was written
 * when there were two destinations and a way out; there are now eight, which is why it needs
 * a current-page state and why it must stay a row of text rather than growing into chrome.
 *
 * A row of text, not a chrome. [NOVO] carries layout with whitespace, and a product with two
 * screens does not need a header bar competing with the one action on each of them
 * (design principle 1).
 */
.bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    /* Tight enough that eight destinations and the way out fit one line on a laptop. At
     * --space-sm they came to 664px against a 640px measure, so "Sign out" wrapped alone onto
     * a second row and the bar cost twice the height for one word. The links are 44px tall
     * and separated only horizontally, so this is spacing, not target size. */
    gap: var(--space-xs);
    /* Trimmed below the rule and above it. Six destinations wrap to two rows on a phone and
     * always will at these label lengths, so the height that can be recovered is the padding
     * around them — which is where the step screen's fold pixels were going. */
    padding: 0 0 var(--space-xs);
    border-bottom: var(--border-width) solid var(--colour-border);
    margin-bottom: var(--space-md);
    font-size: var(--font-size-sm);
}

/* NO UNDERLINE, AND THIS IS A CHANGE. Eight destinations each carrying a link underline read
 * as a paragraph of links rather than as navigation, and left nothing in reserve to mark the
 * page you are on. They sit inside a labelled <nav>, so nothing depends on the underline to
 * identify them; it comes back on hover and focus, where it is doing work.
 *
 * The height stays 44px: WCAG 2.2 AA 2.5.8 governs the target, not the decoration. */
.bar__link {
    min-height: var(--touch-target-min);
    display: inline-flex;
    align-items: center;
    color: var(--colour-primary);
    text-decoration: none;
}

.bar__link:hover,
.bar__link:focus-visible {
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

/* Where you are. Weight and a rule, never colour alone (WCAG 2.2 AA, 1.4.1) — and the
 * attribute that draws it is the same one that tells a screen reader, so the two cannot
 * drift apart. */
.bar__link[aria-current='page'] {
    box-shadow: inset 0 -2px 0 0 var(--colour-primary);
    font-weight: var(--font-weight-medium);
}

.bar__link[aria-current='page']:hover,
.bar__link[aria-current='page']:focus-visible {
    text-decoration: none;
}

/* Sign out is a <button> because a GET logout fires on any prefetch, but inside the bar it is
 * one of the destinations to the eye and is dressed like them. Elsewhere .link-button keeps
 * its underline, which is what marks it as a control at all. */
.bar .link-button {
    min-height: var(--touch-target-min);
    text-decoration: none;
}

.bar .link-button:hover,
.bar .link-button:focus-visible {
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

/* Pushed to the far edge, ONCE THERE IS AN EDGE TO PUSH TO. On a phone the bar wraps to three
 * rows, and margin-left:auto stranded "Sign out" alone on a fourth — 44px of the first screen
 * spent on the one thing a participant is least likely to want. It joins the flow when the
 * row wraps and takes its own end of the line when it does not. */
@media (min-width: 40em) {
    .bar__out {
        margin-left: auto;
    }
}

/* An action with a link's weight.
 *
 * Used where a real action must not compete with the primary one — the onward link on a team
 * that still needs colleagues, and the save action on the high-step question. It stays a real
 * <a> or <button>, so it is keyboard operable and needs no JavaScript.
 *
 * FONT AND UNDERLINE ARE DECLARED, NOT INHERITED, and both were missing. This class was
 * written for an <a>, where the UA supplies an underline and the font inherits from the page.
 * A <button> gets neither: form controls take their font from the UA stylesheet, so the
 * control rendered in the browser's own form font — a THIRD typeface on the page in Gecko and
 * WebKit, which design contract §2 forbids outright — at roughly 13px beside an 18px button.
 * And with no underline, no border, no background, and --colour-primary resolving to the same
 * True Blue as body text, the only thing marking it as a control at all was font weight.
 *
 * On the screen where most people who arrive genuinely walked the steps, that made the action
 * they need the one that did not look like an action. Every other control in this file already
 * declares both — .button, .link-button, .field__input — so this is the outlier being brought
 * into line rather than a new rule. */
.text-link {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
    color: var(--colour-primary);
    font-family: inherit;
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-medium);
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

/* --- The high-value question --------------------------------------------------------------------
 * One question, two answers, nothing else on the page.
 *
 * The two actions are deliberately UNEQUAL in weight and equal in reach. "Go back and edit" is
 * the likelier correct answer for somebody who mistyped a zero, so it reads first and carries
 * the solid treatment; saving is a plain control beside it. Both are keyboard reachable in the
 * order they are read, and neither is hidden behind the other.
 *
 * Nothing here depends on colour. The two labels say what they do — one of them names the
 * number — so the decision survives greyscale and a screen reader alike (WCAG 2.2 AA, 1.4.1).
 */
.confirm__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
    margin-bottom: var(--space-md);
}

/* The house pattern: full width on a phone, content width from 40rem.
 *
 * An earlier version forced `width: auto` so the two actions would sit side by side on a
 * phone. Design review did the arithmetic: at 320px the edit button is roughly 180px of the
 * ~288px available, so the save action wraps to its own line anyway — the deviation without
 * the benefit it was made for, and a narrow primary button where every other screen in this
 * product gives a full-width one. */
.confirm__edit {
    width: 100%;
}

@media (min-width: 30rem) {
    .confirm__edit {
        width: auto;
    }
}

.confirm__save {
    /* A real submit button wearing a link's weight — see .text-link for why that treatment
     * exists. It keeps the 44px target the token layer asks for. */
    padding: 0;
}

/* --- The administrative screen ------------------------------------------------------------
 *
 * The first admin surface in the product, and the first one that shipped with no styles of
 * its own — design review caught that the two <fieldset> elements were falling back to the
 * browser's default groove border, which is a grey outside the eleven official Novo values.
 * A foreign colour entering by omission is the exact risk .text-link was written to close, so
 * the same treatment applies here: state every property that carries meaning.
 */
.admin__group {
    margin: 0 0 var(--space-lg);
    padding: var(--space-md);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-md);
}

/* The legend names what the group is FOR, and the two groups on this screen exist to keep
 * calendar dates and global instants apart. It carries weight rather than colour so the
 * distinction survives without hue (WCAG 2.2 AA, 1.4.1). */
.admin__legend {
    padding: 0 var(--space-2xs);
    font-weight: var(--font-weight-bold);
}

/* The group's own note — the sentence that says whether these values are local days or
 * worldwide moments. Muted and small, matching .gate__hint, so it reads as guidance attached
 * to the group rather than as another field label. */
.admin__note {
    margin: 0 0 var(--space-md);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.admin__section {
    margin-top: var(--space-2xl);
}

.admin__heading {
    margin: 0 0 var(--space-sm);
    font-size: var(--font-size-lg);
}

/* --- The audit trail ---------------------------------------------------------------------
 *
 * Each entry is three spans. Unstyled they collapsed onto one run-on line — "Registration closes
 * changed from not set to 2026-10-02 06:34 Europe/Copenhagen by Mette Holm, 4 Sep 2026 08:34"
 * — which is the least readable possible form for the one thing somebody comes here to scan.
 */
.history {
    margin: 0;
    padding: 0;
    list-style: none;
}

.history__entry {
    padding: var(--space-sm) 0;
    border-bottom: var(--border-width) solid var(--colour-border);
}

.history__entry:last-child {
    border-bottom: 0;
}

/* THREE LINES, from AdminCampaign.dc.html: the field at full strength, because it is the thing
 * being looked for; old → new beneath it; then who and when, needed to trust the entry rather
 * than to find it. */
.history__field {
    display: block;
    font-size: 15px;
    font-weight: var(--font-weight-bold);
}

.history__change {
    display: block;
    margin-top: 4px;
    color: var(--colour-text-muted);
    font-size: 15px;
    overflow-wrap: anywhere;
}

.history__who {
    display: block;
    margin-top: 6px;
    color: var(--colour-text-muted);
    font-size: 13px;
}

/* The rest of the history, behind a native disclosure: the summary is a real control, 44px high,
 * in the text colour, with the product's focus ring. */
.history__more {
    border-top: var(--border-width) solid var(--colour-border);
}

/* A list item, not flex: flex would drop the native disclosure triangle, the one cue that the line
 * opens. The padding makes it 44px high. */
.history__toggle {
    display: list-item;
    padding: 12px 0;
    line-height: 20px;
    font-size: 14px;
    font-weight: var(--font-weight-bold);
    color: var(--colour-text);
    cursor: pointer;
}

.history__toggle:focus-visible {
    outline: var(--focus-ring-width) solid var(--colour-focus);
    outline-offset: var(--focus-ring-offset);
}

/* --- The error summary's list ------------------------------------------------------------
 * One line per refused field, each a link to it. Inherits .status--error's colour, so the
 * links carry an underline rather than a hue of their own — see .status__link. */
.status__list {
    margin: var(--space-2xs) 0 0;
    padding-left: var(--space-md);
}

/* --- A setting that can no longer be changed ----------------------------------------------
 *
 * Rendered as a fact rather than as a disabled control. A greyed-out input still reads as
 * something you might be able to use, and announces itself to assistive technology as an
 * unavailable form field — which poses the question without answering it. The value stands as
 * text; the reason stands beside it.
 */
.field--locked {
    margin-bottom: var(--space-md);
}

.locked__value {
    margin: var(--space-3xs) 0 var(--space-2xs);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-medium);
}

/* The reason, in the muted voice the hints use — it is guidance, not an error. Nothing about
 * this state is a failure, so it must not wear the error palette. */
.locked__reason {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* The locked name/value pair. A definition list, so the label and the value are related in
 * the markup rather than only by proximity. */
.locked {
    margin: 0;
}

.locked dd {
    margin: 0;
}

/* The reason, once per group. It is guidance, not an error, so it wears the muted voice the
 * hints use rather than the error palette. */
.admin__note--locked {
    color: var(--colour-text-muted);
}

/* --- A decision the participant has to make ------------------------------------------------
 *
 * Shared by moving teams, creating your own team while on one, and removing a member. All
 * three ask the same kind of question — "this will change who you are walking with, is that
 * what you want" — so they get one shape, and a participant who has seen one recognises the
 * next.
 *
 * Generous space, one heading, one consequence, one reassurance, then the actions. Nothing
 * competes with the sentence that says what will happen.
 */
.decision {
    max-width: 34rem;
    margin: 0 auto;
    padding: var(--space-lg) 0 var(--space-2xl);
}

.decision__header {
    margin-bottom: var(--space-lg);
}

/* A confirm-before-you-act page is an admin page: same title step. */
.decision__heading {
    margin: 0;
    font-size: var(--font-size-2xl);
    line-height: var(--line-height-tight);
}

.decision__lede {
    margin: 0 0 var(--space-sm);
    font-size: var(--font-size-lg);
    line-height: var(--line-height-base);
}

/* What survives the change. Muted, because it is reassurance rather than the decision — but
 * present on every one of these screens, because "will I lose my steps" is the question
 * nobody should have to ask. */
/* ONE GAP BETWEEN THE SENTENCES AND A BIGGER ONE BEFORE THE ANSWER. The bottom margin used to
 * be the large one, which was right while there was a single sentence and wrong the moment the
 * removal card gained a second: the two ran together and a chasm opened before the third. */
.decision__keeps {
    margin: 0 0 var(--space-sm);
    color: var(--colour-text-muted);
    line-height: var(--line-height-base);
}

.decision__form {
    margin-bottom: var(--space-md);
}

/* THE CONFIRM AND THE WAY OUT, SIDE BY SIDE WHERE THERE IS ROOM.
 *
 * CaptainActions.dc.html draws both as buttons on one line, the answer filled and the way out
 * outlined, and it is right about the shape: this page exists to ask one question, so the
 * answer is the page's primary action rather than a quieter one, and "no" gets the same target
 * as "yes" instead of being a line of underlined text under it.
 *
 * STACKED ON A PHONE, which is the reason the old rule gave for stacking everywhere: side by
 * side at 320px the two are cramped enough to mistap, and a mistap here moves somebody out of
 * their team. The reason was good and the scope was wrong. */
.decision__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    align-items: center;
    margin-top: var(--space-lg);
}

@media (max-width: 26rem) {
    .decision__actions {
        flex-direction: column;
        align-items: stretch;
    }

    .decision__actions form,
    .decision__actions .button {
        width: 100%;
    }
}

/* Declining writes nothing, and it used to be a link for that reason — given real prominence
 * rather than hidden, because "no" is a perfectly good answer here. It is a quiet BUTTON now,
 * which says the same thing with the same target as the answer beside it (WCAG 2.2 AA 2.5.8)
 * and is what the board draws.
 *
 * An earlier version set line-height to the target height, which made a long team name
 * wrap into two 44px lines. */
.decision__decline {
    display: inline-block;
}

/* --- The two teams, and the direction of travel --------------------------------------------
 *
 * The team being LEFT is rendered at equal weight to the one being joined. That is the whole
 * point of the component: somebody clicking an invitation is thinking about where they are
 * going, and what they will regret is what they left without noticing.
 */
.move {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    align-items: stretch;
    margin-bottom: var(--space-lg);
}

.move__side {
    flex: 1 1 8rem;
    padding: var(--space-sm) var(--space-md);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-md);
    background: var(--colour-surface-sunken);
}

/* The destination carries a heavier edge so the direction is legible at a glance — but the
 * words "Leaving" and "Joining" above each side say it too, so nothing depends on the border
 * (WCAG 2.2 AA, 1.4.1). */
.move__side--target {
    border-color: var(--colour-border-strong);
    border-left-width: var(--border-width-accent);
    background: var(--colour-surface-raised);
}

.move__role {
    display: block;
    margin-bottom: var(--space-3xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: var(--tracking-caps);
}

.move__team {
    display: block;
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-medium);
    line-height: var(--line-height-tight);
}

/* Decorative, and hidden from assistive technology. It reinforces a direction the "Leaving"
 * and "Joining" labels already state in words.
 *
 * HIDDEN ON NARROW SCREENS. At 320px the two sides cannot sit side by side, so the second wraps
 * below and the arrow is left at the end of the first line pointing right at nothing. The
 * labels carry the direction on their own, so the honest fix is to drop the glyph rather than
 * to reposition something that means nothing there. */
.move__arrow {
    display: none;
    align-self: center;
    color: var(--colour-text-muted);
    font-size: var(--font-size-lg);
}

@media (min-width: 30rem) {
    .move__arrow {
        display: inline;
    }
}

/* --- The captain's per-member removal -------------------------------------------------------
 * A link to a confirmation, not an inline destructive control: removing somebody should not be
 * one stray tap on a phone. Sized to the touch-target minimum and underlined, so it is
 * recognisable as a control without borrowing the palette's danger colour for something that
 * destroys nothing.
 */
.roster__remove {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
    padding: 0 var(--space-2xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.roster__remove:hover,
.roster__remove:focus-visible {
    color: var(--colour-text);
}

/* The product's first secondary button: a real button at the standard target size, in the
 * outline treatment rather than solid.
 *
 * NAMED FOR WHAT IT IS, not for a feeling. It was ".button--caution", which promised a
 * semantic the copy on the same screen spends three sentences arguing against — removing a
 * member destroys nothing — and would have forced the next ordinary secondary button either to
 * misuse the name or to duplicate the rule. */
.button--secondary {
    background: var(--colour-surface-raised);
    color: var(--colour-text);
    border: var(--border-width-strong) solid var(--colour-border-strong);
}

.button--secondary:hover {
    background: var(--colour-surface-sunken);
}

.team__note {
    margin: var(--space-md) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

/* --- The support workspace -----------------------------------------------------------------
 *
 * Denser than a participant screen and deliberately so: an operator reads this many times a day
 * with somebody on the line, and whitespace that helps a participant read one page slowly gets
 * in their way. Density is not clutter — nothing here is decorative, and the hierarchy is
 * carried by size and weight rather than by rules and boxes.
 */
/* --- The admin surfaces' container ---------------------------------------------------------
 * The campaign settings and finalisation screens use .admin/.admin__header, and neither had a
 * rule: no measure, no header spacing. Design review found it — the inner elements
 * (.admin__group, .admin__note, .admin__legend) were all styled, so the omission looked
 * deliberate and read as a slightly different screen rather than an unstyled one.
 *
 * Deliberately the same shape as .support below. Both are admin surfaces read by the same
 * people, and a different measure between them would be a difference nobody chose.
 */
.admin {
    max-width: 46rem;
    margin: 0 auto;
    padding-bottom: var(--space-2xl);
}

.admin__header {
    margin-bottom: var(--space-lg);
}

/* The forms on these screens are the page's content rather than a panel within it, so they
 * carry the vertical rhythm the fieldsets inside them rely on. */
.admin__form {
    margin-top: var(--space-lg);
}

.support {
    max-width: 46rem;
    margin: 0 auto;
    padding-bottom: var(--space-2xl);
}

/* A LIST OF PEOPLE IS NOT A RECORD. The 46rem measure is right for one participant's page and
 * wrong for the population: five columns inside it left every address clipped and the filters
 * stacked in a narrow box. The wide modifier is the same component at table width. */
.support--wide {
    max-width: none;
}

.support__header {
    margin-bottom: var(--space-lg);
}

/* THE ADMIN PAGE TITLE, AND THE PRODUCT'S TWO-LEVEL RULE.
 *
 * Participant and public screens lead with --font-size-3xl; administration leads one step below
 * it, at 2xl. That is deliberate rather than an accident of who wrote which screen: an admin
 * page is a working surface reached many times a day, usually carrying a filter row and a table,
 * and a 36px title spends the fold on something the operator already knows.
 *
 * WHAT WAS ACTUALLY WRONG WAS THE INCONSISTENCY. Fifteen admin screens used this class at 22px
 * while eight had no class at all and inherited the participant 36px — so administration
 * disagreed with itself depending on which screen you opened. Every admin title now carries this
 * class, and the campaign, finalise, competition and MFA screens were the ones missing it. */
.support__heading {
    margin: 0;
    font-size: var(--font-size-2xl);
    line-height: var(--line-height-tight);
}

.support__lede {
    margin: var(--space-2xs) 0 0;
    color: var(--colour-text-muted);
}

/* The search box IS the page. An operator opening the workspace is always looking for
 * somebody, so it gets the width, the focus and the only primary button above the fold. */
.support__search {
    margin-bottom: var(--space-xl);
}

.support__search-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    align-items: flex-start;
    margin-top: var(--space-2xs);
}

.support__search-row .field__input {
    flex: 1 1 16rem;
}

.support__results-for {
    margin: 0 0 var(--space-md);
    color: var(--colour-text-muted);
}

.support__section {
    margin-top: var(--space-xl);
}

.support__section-heading {
    margin: 0 0 var(--space-sm);
    font-size: var(--font-size-lg);
}

.support__note {
    margin: 0 0 var(--space-md);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

.support__form {
    max-width: 32rem;
}

.support__actions {
    margin: var(--space-md) 0 0;
}

.support__onward {
    margin-top: var(--space-lg);
}

/* --- The support audit trail ----------------------------------------------------------------
 * What happened, then who and when, then why. The order is the order an operator reads it in.
 */
.audit {
    margin: 0;
    padding: 0;
    list-style: none;
}

.audit__entry {
    padding: var(--space-sm) 0;
    border-bottom: var(--border-width) solid var(--colour-border);
}

.audit__entry:last-child {
    border-bottom: 0;
}

.audit__what {
    display: block;
}

.audit__who {
    display: block;
    margin-top: var(--space-3xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* The operator's own words. Set apart so it reads as a quotation of an internal note rather
 * than as product copy. */
.audit__reason {
    display: block;
    margin-top: var(--space-3xs);
    padding-left: var(--space-2xs);
    border-left: var(--border-width-accent) solid var(--colour-border);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* --- The language switcher ------------------------------------------------------------------
 * In the footer, quiet, and available to guests and participants alike.
 */
.page__footer {
    margin-top: var(--space-2xl);
    padding-top: var(--space-md);
    border-top: var(--border-width) solid var(--colour-border);
}

.language {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs) var(--space-sm);
    align-items: center;
}

.language__label {
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.language__options {
    display: flex;
    gap: var(--space-2xs);
    align-items: center;
}

/* The current language reads as state, not as an offer: it is not a button, and it carries
 * aria-current plus a visually hidden "(current language)" so the distinction is not made by
 * appearance alone. */
/* THE CURRENT LANGUAGE HAS TO LOOK CURRENT.
 *
 * The markup was already right — aria-current on the one you are reading, a real button on the
 * other, and a visually-hidden "(current language)" beside it — but the styling said the
 * opposite: the ALTERNATE was primary blue and underlined, which is what everybody reads as
 * "selected", while the current one was plain text in a lighter weight. A Danish reader saw
 * English marked and Dansk unmarked.
 *
 * So the current one is the strongest thing in the group — full text colour, bold, and not a
 * link — and the alternate is muted and underlined, which is what an available action looks
 * like. The approved gate footer draws exactly this: the current in dark bold, the other quiet
 * beside it.
 */
.language__current {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
    padding: 0 var(--space-2xs);
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

.language__choice {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
    padding: 0 var(--space-2xs);
    border: 0;
    background: none;
    color: var(--colour-text-muted);
    font-family: inherit;
    font-size: var(--font-size-sm);
    text-decoration: underline;
    cursor: pointer;
}

.language__choice:hover {
    color: var(--colour-primary-hover);
}

/* --- Paging a search -------------------------------------------------------------------------
 * A count and two controls, not a row of page numbers. The count is the useful part: an
 * operator who reads "16 to 30 of 43" learns their search was too broad, which is a better
 * next action than paging through it.
 */
.pager {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs) var(--space-md);
    align-items: baseline;
    justify-content: space-between;
    margin-top: var(--space-sm);
}

.pager__count {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* Two forms side by side. Each is a real POST carrying the search term in its body, because the
 * term is a name or a work address and must not reach a URL. */
.pager__controls {
    display: flex;
    gap: var(--space-md);
    align-items: center;
}

/* Long work addresses and long Danish compounds must wrap rather than overflow at 320px, the
 * same rule .roster__name already carries. */
.support__heading,
.decision__heading {
    overflow-wrap: anywhere;
}

/* A support-history entry recorded before reasons were structured. Marked so a reader can tell
 * an operator's own words from a chosen category, rather than being left to guess which they
 * are looking at. Muted and small: it is provenance, not content. */
.audit__legacy {
    display: block;
    margin-top: var(--space-3xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
}

/* --- A grouped pair of questions inside a gate form -----------------------------------------
 * Country and EVP area are one thing with one purpose, so they sit in a fieldset with a short
 * explanation rather than as two more fields on a growing list. Borrowed shape from the admin
 * screen's .admin__group, kept lighter because a participant sees this once.
 */
.gate__group {
    /* The preceding .field already contributes its own bottom margin, and the form's flex gap
     * sits on top of that, so a full --space-lg here stacked into roughly eighty pixels of
     * nothing between the time zone hint and this fieldset. Measured in a browser at 390px;
     * the three contributions are invisible when reading any one rule. */
    margin: var(--space-xs) 0 0;
    padding: var(--space-md);
    border: 0;
    border-radius: var(--radius-md);
    /* TINT RATHER THAN AN OUTLINE, and it used to be an outline. On a phone that put a third
     * container inside the second one — an outlined box, inside a white card, on the tinted
     * gate ground — which is the layered clutter the design manual asks to remove. The tint is
     * the same grouped-block idiom the today panel uses on the step screen, so the journey
     * arrives at step entry having already learned what a grouped block looks like. */
    background: var(--colour-surface-sunken);
}

/* FLOATED, WHICH LOOKS ODD AND IS THE POINT. A <legend> is not laid out inside its fieldset:
 * the browser places it across the block-start border, so with the outline gone the heading
 * hung above the tinted block and the tint began underneath its baseline. Floating the legend
 * takes it out of that special placement and makes it an ordinary block inside the padding,
 * which is the only way to get it onto the ground it names without leaving the element. */
.gate__legend {
    float: left;
    width: 100%;
    margin-bottom: var(--space-2xs);
    padding: 0;
    font-weight: var(--font-weight-bold);
}

/* The float above has to be contained, or the fieldset collapses to its padding. */
.gate__group::after {
    content: '';
    display: table;
    clear: both;
}

/* The "why we ask" sentence. Muted and small, matching .gate__hint, so it reads as guidance
 * attached to the group rather than as another label. */
.gate__note {
    margin: 0 0 var(--space-md);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

/*
 * ONE CARD FAMILY. .gate became a raised card when the first-run screens were made to feel
 * like one flow, and .card - competitions, standings summaries - stayed flat, so the same
 * product had two ideas of what a panel is. They are now the same idea: a raised surface with
 * the shadow token, which is what makes a stack of them read as separate things rather than
 * as one long ruled page.
 */
.card {
    padding: var(--space-md);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-md);
    background: var(--colour-surface-raised);
    box-shadow: var(--shadow-sm);
}

@media (min-width: 40em) {
    .card {
        padding: var(--space-lg);
    }
}

/* Consecutive cards need air between them; without it the shadows touch and the stack reads
 * as one block with lines through it. */
.card + .card {
    margin-top: var(--space-md);
}

/* A card's own parts, still used by the admin competition screens, the erasure confirmation and
 * the diploma. The standings' variants went with the standings' cards; these did not. */
.card__label {
    margin: 0 0 var(--space-2xs);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    color: var(--colour-text-muted);
}

/* `overflow-wrap` on the base rather than one modifier: a card detail is where an address or a
 * team name lands, and either can be a single token longer than a 320px viewport. Without it the
 * card is pushed wider than the screen and the page scrolls sideways (WCAG 1.4.10). */
.card__detail {
    margin: var(--space-2xs) 0 0;
    color: var(--colour-text-muted);
    overflow-wrap: anywhere;
}

.card__detail--quiet {
    font-size: var(--font-size-sm);
}

/* THE OLD STANDINGS SCREEN'S RULES LIVED HERE, and went with the screen.

 * The approved Stilling design replaced a stack of cards, a pair of link tabs and an <ol>
 * leaderboard with a band, a segmented control and a real table — all of which are declared in the
 * STILLING section at the end of this file, out of the same parts as the other participant
 * screens. The rules that served the old markup are deleted rather than left dormant: a
 * stylesheet that describes elements no template renders is a map of a building that has been
 * pulled down, and the next person to read it has no way to know which half is still standing.
 */

/* --- A page that is only a message ------------------------------------------------------------
 * One heading, a sentence or two, and the way back.
 *
 * IT WAS CALLED .pause, AFTER THE ONE PAGE THAT USED IT. The throttle page is a message page, and
 * so is every error page — what happened, and what to do now — so the component is named for the
 * shape rather than for the first screen that needed it.
 *
 * CONSTRAINED TO THE READING MEASURE. These pages are read once, quickly, usually by somebody
 * who did not expect to be here; a line of text spanning a desktop is the wrong shape for that.
 */
.message {
    max-width: var(--layout-measure);
}

.message__heading {
    margin: 0 0 var(--space-sm);
}

.message__body {
    margin: 0 0 var(--space-sm);
    color: var(--colour-text-muted);
}

.message__actions {
    margin: var(--space-md) 0 0;
}

/* --- Competitions ----------------------------------------------------------------------------
 * Three things on offer, said plainly.
 *
 * DELIBERATELY UNDECORATED. A campaign about walking should not read like a betting product, so
 * there is no odds treatment, no counter, no motion and nothing that resembles a machine paying
 * out. The competitions reuse the card the rest of the product uses, and the only thing that
 * varies is a status line whose meaning is carried by words rather than by its colour.
 */
.competitions__header,
.competitions-admin .competitions__header {
    margin-bottom: var(--space-lg);
}

.competitions__status {
    margin-top: var(--space-md);
    padding-top: var(--space-sm);
    border-top: var(--border-width) solid var(--colour-border);
}

.competitions__status-heading {
    margin: 0 0 var(--space-xs);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

/*
 * Status is stated in words; this only reinforces it, and never carries it (WCAG 1.4.1).
 *
 * ONE CLASS, NOT TWO. There were a --yes and a --no, and they rendered identically — the same
 * weight, and a colour on --no that .card__detail had already set. Two names implying a
 * distinction the stylesheet does not make is worse than one name that is honest about it.
 */
.competitions__status-line {
    font-weight: var(--font-weight-medium);
}

.competitions-admin__winner {
    margin-top: var(--space-sm);
    padding: var(--space-sm);
    background: var(--colour-surface-sunken);
}

.competitions-admin__winner-heading {
    margin: 0 0 var(--space-xs);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

.competitions-admin__teams {
    margin: 0;
    padding: 0;
    list-style: none;
    font-weight: var(--font-weight-medium);

    /* Team names are participant-authored and can be a single long compound; the same rule
       .roster__name and .board__name already carry, for the same reason. */
    overflow-wrap: anywhere;
}

.competitions-admin__flag {
    display: inline-block;
    margin-left: var(--space-xs);
    font-weight: var(--font-weight-regular);
    color: var(--colour-text-muted);
}

.competitions-admin__actions {
    margin: var(--space-md) 0 0;
}

.competitions-admin__history {
    margin-top: var(--space-md);
}

.competitions-admin__history-list {
    margin: var(--space-xs) 0 0;
    padding-left: 0;
    list-style: none;
    color: var(--colour-text-muted);
    overflow-wrap: anywhere;
}

.competitions-admin__history-list > li + li {
    margin-top: var(--space-xs);
}

.competitions-admin__state {
    font-weight: var(--font-weight-medium);
    color: var(--colour-text);
}

/*
 * WHERE A PRIMARY ACTION WOULD HAVE BEEN.
 *
 * Best Team Name has no approved provider, so its panel states that instead of offering a
 * button that cannot work. Deliberately not an error treatment: nothing has gone wrong, the
 * product simply does not have this yet.
 */
.competitions-admin__blocked {
    display: inline-block;
    color: var(--colour-text-muted);
}

/*
 * THE COMPETITION'S NAME.
 *
 * Not .card__label: that is a small, muted caption written to sit above a large figure, and
 * these cards have no figure. Using it here rendered the three competition names smaller and
 * quieter than the paragraphs explaining them, which inverts the reading order.
 */
.competitions__name {
    margin: 0 0 var(--space-xs);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
    color: var(--colour-text);
}

/*
 * THE ONLY RADIO GROUP IN THE PRODUCT, and it had no styling at all — three labels running
 * together as inline text with browser-default controls, below this project's own 44px target
 * floor, on the screen where an administrator records why a draw was annulled.
 */
.field__label {
    display: block;
    margin-bottom: var(--space-xs);
    font-weight: var(--font-weight-medium);
}

.field__choice {
    display: flex;
    gap: var(--space-xs);
    align-items: center;
    min-height: var(--touch-target-min);
}

.field__choice input {
    /* Larger than the browser default, so the control is a real target rather than a dot. */
    width: 1.25rem;
    height: 1.25rem;
    margin: 0;
    flex: none;

    /* The product's first native binary control. Without this the selected dot and ring render
       in the user agent's accent colour — a blue that is not True Blue and not one of the
       eleven official values. A brand colour drifts in by omission as easily as by a hex. */
    accent-color: var(--colour-primary);
}

/*
 * The winning team named on the annul confirmation. Participant-authored, up to eighty
 * characters, and permitted to contain no whitespace at all — so it wraps, like every other
 * place this product prints one.
 */
.competitions-admin__named-draw {
    overflow-wrap: anywhere;
}

/*
 * The history disclosure, matching .day__summary rather than inventing a second treatment:
 * the same 44px floor and the same suppression of a native marker browsers draw inconsistently
 * and in a colour that is not ours.
 */
.competitions-admin__history summary {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    min-height: var(--touch-target-min);
    cursor: pointer;
    list-style: none;
}

.competitions-admin__history summary::-webkit-details-marker {
    display: none;
}

/* --- Diplomas ---------------------------------------------------------------------------------
 *
 * A completion artefact, and the design says so: no ribbons, no seals, no gold. The certificate
 * is the product's own type and palette given room — True Blue on Snow White, one large figure,
 * generous space — which is what makes it read as premium rather than as a template somebody
 * downloaded. [NOVO] §3: remove the superfluous.
 */
.diplomas__header {
    margin-bottom: var(--space-lg);
}

.diplomas__actions {
    margin: var(--space-md) 0 0;
}

.diplomas__hint {
    margin-top: var(--space-lg);
    color: var(--colour-text-muted);
}

.diploma-page {
    max-width: var(--layout-measure);
}

.diploma-page__controls {
    margin: 0 0 var(--space-md);
    color: var(--colour-text-muted);
}

.diploma-page__controls + .diploma {
    margin-top: 0;
}

/*
 * THE CERTIFICATE.
 *
 * A single bordered field with everything centred, which is the one place in this product where
 * centred text is right: it is a document to be looked at rather than a screen to be read down.
 * The border is the product's own border token rather than a decorative frame.
 */
.diploma {
    padding: var(--space-xl) var(--space-lg);
    text-align: center;
    background: var(--colour-surface);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-md);
}

.diploma__eyebrow {
    margin: 0 0 var(--space-lg);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--colour-text-muted);
}

.diploma__campaign {
    margin: 0 0 var(--space-2xs);
    font-size: var(--font-size-xl);
}

.diploma__period {
    margin: 0 0 var(--space-xl);
    color: var(--colour-text-muted);
}

.diploma__awarded,
.diploma__took-part {
    margin: 0;
    color: var(--colour-text-muted);
}

/* The name, which is the reason somebody keeps the thing. */
.diploma__name {
    margin: var(--space-2xs) 0 var(--space-lg);
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-bold);
    line-height: 1.15;

    /* Participant and team names are supplied text and can be long compounds in Danish. */
    overflow-wrap: anywhere;
}

.diploma__figure {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs);
    align-items: baseline;
    justify-content: center;
    margin: var(--space-2xs) 0 var(--space-md);
}

.diploma__number {
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-bold);
    line-height: 1.1;

    /* Tabular figures so a long number reads as a quantity rather than as text. */
    font-variant-numeric: tabular-nums;
}

.diploma__unit {
    color: var(--colour-text-muted);
}

.diploma__detail {
    margin: 0 0 var(--space-md);
    font-size: var(--font-size-sm);
    color: var(--colour-text-muted);
}

.diploma__place {
    margin: 0;
    font-weight: var(--font-weight-medium);
}

@media (min-width: 40rem) {
    .diploma {
        padding: var(--space-2xl);
    }

    .diploma__name {
        font-size: calc(var(--font-size-2xl) * 1.4);
    }

    .diploma__number {
        font-size: calc(var(--font-size-2xl) * 1.4);
    }
}

/*
 * ON PAPER.
 *
 * The browser prints this; there is no PDF library in this product and none is wanted for a page
 * every browser already renders to paper and to PDF. What print needs is the page furniture gone
 * — navigation, footer, the link back — so the sheet carries the certificate alone, and the
 * border kept, because a certificate without its edge is a paragraph.
 */
@media print {
    .no-print,
    .bar,
    .page__footer,
    .skip-link {
        display: none !important;
    }

    .page {
        padding: 0;
    }

    .diploma {
        /* Never split across two sheets. */
        break-inside: avoid;
        border-color: var(--colour-text);
    }

    /* Print backgrounds are commonly dropped; the design does not depend on any. */
    .diploma__number,
    .diploma__name {
        color: var(--colour-text);
    }
}

/* --- Two-step sign-in --------------------------------------------------------------------
 * The administrator code screens (enrolment, the challenge, re-authentication). One task per
 * screen: somebody here is part-way through signing in and wants to be finished, not impressed.
 * They sit in the gate card (layouts/gate); the card's own parts are at the end of this sheet.
 */
/* The numbered steps carry meaning — they are an order to follow — so this is an <ol>. In the code
 * card (the end of this sheet) its numbers are drawn by a counter and role="list" keeps it a list. */
.mfa__steps {
    margin: 0;
    padding-left: var(--space-lg);
    display: flex;
    flex-direction: column;
    gap: var(--space-xl);
}

.mfa__step-title {
    margin: 0 0 var(--space-2xs);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-medium);
    color: var(--colour-text);
}

.mfa__step-detail {
    margin: 0 0 var(--space-sm);
    color: var(--colour-text-muted);
}

/* The QR sizes itself to the column and stops growing on a wide screen — a 600px QR code is not
 * easier to scan, only louder. */
.mfa__qr {
    max-width: 15rem;
    margin: 0 0 var(--space-md);
    padding: var(--space-sm);
    background: var(--colour-surface);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-md);
}

.mfa__qr svg {
    display: block;
    width: 100%;
    height: auto;
}

.mfa__manual-label {
    margin: 0 0 var(--space-2xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* Spaced and tabular, because this is read aloud and typed by hand.
 *
 * NO MONOSPACE FAMILY, because this design system does not define one and inventing a token for
 * one screen is how a type scale acquires a second, undocumented half. Tabular figures plus the
 * grouping the controller applies give the same alignment the key actually needs.
 *
 * `user-select: all` makes one tap select the whole key on a phone, which is the closest thing
 * to a copy button that needs no JavaScript. */
.mfa__manual-key {
    margin: 0 0 var(--space-xs);
    padding: var(--space-xs);
    background: var(--colour-surface-sunken);
    border-radius: var(--radius-sm);
    font-size: var(--font-size-lg);
    font-variant-numeric: tabular-nums;
    letter-spacing: var(--tracking-code);
    overflow-wrap: anywhere;
    user-select: all;
}

.mfa__form {
    margin-top: var(--space-md);
}

/* The sentence under the code field. Its own class rather than .campaign__hint, which belongs
 * to the step screen and carries that screen's spacing. */
.mfa__hint {
    margin: var(--space-2xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* Tabular figures so the digits do not shift as they are typed. In the code card (the end of this
 * sheet) the field takes the card's width, large and centred. */
.mfa__code {
    max-width: 10rem;
    font-size: var(--font-size-lg);
    /* Wider than the setup key: six digits typed one at a time, where the gap between characters
     * is what stops a transposed pair going unnoticed. */
    letter-spacing: calc(var(--tracking-code) * 2.5);
    font-variant-numeric: tabular-nums;
}

.mfa__actions {
    margin: var(--space-md) 0 0;
}

/* --- Erasing a participant ------------------------------------------------------------------
 * The one screen in this product that destroys something. Narrow, quiet, and deliberately not
 * dramatic: an operator here is doing something ordinary and serious, and a screen that shouts
 * would be harder to read carefully rather than easier.
 *
 * NO RED BUTTON. Lava Red is an accent in this design system and never a fill behind text — the
 * contract is explicit, and inventing a destructive-red button would be the one place in the
 * product that broke it. What marks the action as destructive is the words on it, the list of
 * what goes, and a checkbox that has to be ticked. None of that depends on colour, which is also
 * what WCAG 1.4.1 asks for.
 */
.erase {
    max-width: var(--layout-measure);
}

.erase__header {
    margin-bottom: var(--space-lg);
}

/* The name, at the size somebody actually reads before an irreversible action. */
.erase__identity {
    margin: 0 0 var(--space-2xs);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-medium);
    color: var(--colour-text);
    overflow-wrap: anywhere;
}

.erase__list {
    margin: 0 0 var(--space-md);
    padding-left: var(--space-lg);
    color: var(--colour-text);
    line-height: var(--line-height-base);
}

.erase__note {
    margin: var(--space-2xs) 0 0;
    color: var(--colour-status-text);
    line-height: var(--line-height-base);
}

.erase__form {
    margin-top: var(--space-lg);
}

/* The checkbox and its sentence on one line, with the box able to shrink but never the label's
 * hit area — the whole label is the target, which is what makes it usable on a phone. */
.erase__confirm {
    display: flex;
    align-items: flex-start;
    gap: var(--space-xs);
    min-height: var(--touch-target-min);
    cursor: pointer;
    line-height: var(--line-height-base);
}

.erase__confirm input {
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.15rem;
}

.erase__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-md);
    margin: var(--space-lg) 0 0;
}

/* The endorsing brand mark.
 *
 * SIZED BY WIDTH, HEIGHT AUTO. The file is 1300x300; width and height are on the element so
 * the row does not reflow while it loads, and the aspect ratio does the rest.
 *
 * THE CONTRACT'S TWO MEASUREMENTS, honoured rather than eyeballed. Clear space is "no less
 * than the height of two n's": the x-height is roughly 0.3 of this file's height, so at 140px
 * wide the mark is ~32px tall and two n's is ~19px — the --space-md above and below clears it.
 * Minimum size is "no smaller than 15 mm wide", about 57px at 96dpi; 140px is comfortably over,
 * and it does not shrink below that at any width because the value is fixed, not fluid.
 */
.page__brandmark {
    width: 140px;
    height: auto;
    margin-bottom: var(--space-md);
}

.page__operator {
    margin: 0 0 var(--space-md);
    max-width: 60ch;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* Test access: the list of granted addresses and one tester's captured mail.
 *
 * A DELIBERATELY PLAIN SURFACE. Two people use it, both of whom know what it does. What it owes
 * them is legibility at the width they open it, not decoration.
 */
.support__list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: var(--space-2xs);
}

.support__item {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs) var(--space-sm);
    align-items: baseline;
    padding-block: var(--space-2xs);
}

/* The capture time, inside the link so the link text tells them apart. Quieter than the
 * subject, but it is the part that actually distinguishes one row from the next. */
.support__item-time {
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    white-space: nowrap;
}

/* THE WRAPPER SCROLLS, THE PAGE DOES NOT, AND THE TABLE STAYS A TABLE. An address column and
 * a team name are wider than a phone, and a page that scrolls sideways is broken everywhere
 * else on it. The obvious shape — overflow-x on the table — is the wrong one: setting a
 * table's display to block drops its table role, and with it the column headers a screen
 * reader announces for each cell. Two of the five headers here are visually hidden, so that
 * would leave an operator with five unlabelled values per row. tabindex makes the scroll
 * region reachable without a pointer, which is the other half of the same requirement. */
.support__scroller {
    overflow-x: auto;
    /* POSITIONED, SO IT ACTUALLY CONTAINS WHAT IT CLIPS. The cells hold .visually-hidden spans,
     * which are position:absolute — and an absolutely positioned box is clipped by an ancestor's
     * overflow only when that ancestor is its containing block. Static, this scroller clipped the
     * table and let those spans sit at the table's full width against the initial containing
     * block, so the PAGE scrolled sideways by exactly (content - viewport) while the scroller
     * scrolled too. Measured: window.scrollX reached 186 at a 503px viewport; with this, 0. */
    position: relative;
    /* min-width, or the scroller does not scroll. A flex or grid ancestor gives this block an
     * automatic minimum of its content's min-content width, so a wide table pushes the WRAPPER
     * wide instead of scrolling inside it — and the whole page scrolls sideways. Measured at
     * 503 CSS px: without this the table reported 689. The old shape hid it, because a table
     * with display:block was its own scroller. */
    min-width: 0;
    max-width: 100%;
}

.support__table {
    width: 100%;
    border-collapse: collapse;
}

.support__table th,
.support__table td {
    padding: var(--space-2xs) var(--space-sm) var(--space-2xs) 0;
    text-align: left;
    vertical-align: top;
    border-bottom: var(--border-width) solid var(--colour-border);
    white-space: nowrap;
}

/* EXCEPT THE NOTE, which accepts 120 characters. Held on one line it is wider than a phone by
 * itself, and the address — the only thing identifying the row — scrolls out of sight while
 * you read it. */
.support__table .support__cell--wrap {
    white-space: normal;
    min-width: 12rem;
}

/* A captured message's text part. Mail wraps where it likes, so this wraps rather than forcing
 * the page wider — and keeps the newlines, because a sign-in mail reads as lines. */
.support__pre {
    margin: 0;
    padding: var(--space-sm);
    background: var(--colour-surface-sunken);
    border-radius: var(--radius-sm);
    /* The product's own stack, not monospace. A mail body reads perfectly well in it, and the
     * design contract sanctions Apis with an Arial fallback and nothing else — reaching for a
     * monospace face here would be inventing a brand deviation for a screen two people use. */
    font-family: var(--font-family-base);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* Guidance attached to one field.
 *
 * THE CLASS WAS ALREADY IN THE MARKUP WITH NO RULE BEHIND IT — test access has used it since it
 * was built — so the hint rendered at body size and body colour and read as another sentence of
 * the form rather than as help for the field above it. Muted and small, matching .admin__note. */
.field__hint {
    margin: 0 0 var(--space-2xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* The language switch on the email screens.
 *
 * LINKS THAT LOOK LIKE A CHOICE, not a tab widget. There is no scripting here: each one is a
 * GET for the same screen in the other language, so it works before JavaScript and survives a
 * reload. The current one is marked with aria-current and carries weight as well as colour,
 * because colour alone would not say which is showing (WCAG 2.2 AA, 1.4.1). */
.tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs);
    margin: 0 0 var(--space-md);
}

.tabs__tab {
    padding: var(--space-2xs) var(--space-sm);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-sm);
    text-decoration: none;
}

/* THE CURRENT ONE IS FILLED, NOT OUTLINED. A grey fill inside a darker border reads as a pressed
 * button that is now disabled; the soft blue the references use — the same fill the admin
 * navigation's current item carries — reads as "you are here", which is what it means. */
.tabs__tab--current {
    border-color: transparent;
    background: var(--colour-surface-badge);
    color: var(--colour-text);
    font-weight: var(--font-weight-bold);
}

/* A message as a participant would read it, shown inside the admin.
 *
 * A PLAIN BOX, NOT A SIMULATED INBOX. Drawing a fake mail client around it would suggest the
 * preview is pixel-accurate for every recipient, which no email preview can be. It shows the
 * content and the order; the shell is the product's own and is tested elsewhere. */
.email-preview {
    padding: var(--space-md);
    background: var(--colour-surface-sunken);
    border-radius: var(--radius-sm);
    overflow-wrap: anywhere;
}

.email-preview__heading {
    margin: 0 0 var(--space-sm);
    font-size: var(--font-size-lg);
}

.email-preview__cta {
    margin: var(--space-md) 0 0;
    font-weight: var(--font-weight-bold);
}

/* THE IMPERSONATION BANNER.
 *
 * The whole point is that it cannot be missed, so it sits above everything and spans the
 * viewport.
 *
 * TRUE BLUE CARRIES THE TEXT, LAVA RED CARRIES THE ALARM, and the first version had that
 * backwards. It put Snow White on Lava Red and claimed the pairing cleared AA — it does not.
 * tokens.css states the ratio beside the value: 3.66:1, "accent only", which is above the 3:1
 * threshold for a non-text indicator and below the 4.5:1 one for normal text. Review caught the
 * claim. Snow White on True Blue is 15.8:1, so the words are readable, and a thick Lava Red edge
 * does the job the colour is actually sanctioned for. The wording carries the meaning either
 * way (WCAG 2.2 AA, 1.4.1).
 *
 * THE GROUND IS SET FURTHER DOWN, not here. Since the product's own bar became True Blue, this
 * band is the raised tint instead, so that it reads as a warning laid on the chrome rather than as
 * more chrome. The Lava Red rule is 3.34:1 against that tint — still above the 3:1 floor for a
 * non-text indicator — and it is what separates the two, together with the sentence.
 *
 * position: sticky rather than fixed — fixed would sit over content on a short screen and hide
 * whatever the operator scrolled to, which on a support screen is the thing they came to see. */
.impersonation {
    position: sticky;
    top: 0;
    z-index: 100;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs) var(--space-sm);
    align-items: center;
    justify-content: space-between;
    padding: var(--space-2xs) var(--space-md);
    background: var(--colour-primary);
    border-bottom: var(--border-width-accent) solid var(--nn-lava-red);
    color: var(--colour-surface);
}

.impersonation__text {
    margin: 0;
    font-size: var(--font-size-sm);
    line-height: 1.4;
}

.impersonation__exit {
    margin: 0;
}

.impersonation__button:focus-visible {
    outline: var(--border-width-accent) solid var(--colour-surface);
    outline-offset: 2px;
}

/* THE STAGING QA BAR. Staging only; it renders nothing in production.
 *
 * Deliberately NOT the impersonation banner's red: that colour means "you are inside a real
 * colleague's account", and a synthetic QA account is not that. True Blue on a Golden Yellow
 * rule reads as tooling rather than alarm, and the wording carries the meaning for anybody who
 * cannot rely on hue (WCAG 2.2 AA, 1.4.1). White on True Blue is the sanctioned pairing. */
.qabar {
    position: sticky;
    top: 0;
    z-index: 99;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3xs) var(--space-sm);
    align-items: center;
    justify-content: space-between;
    padding: var(--space-3xs) var(--space-md);
    background: var(--colour-primary);
    border-bottom: var(--border-width-accent) solid var(--colour-warning);
    color: var(--colour-text-inverse);
}

.qabar__text,
.qabar__actions {
    margin: 0;
    font-size: var(--font-size-sm);
    line-height: 1.4;
}

.qabar__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
    color: var(--colour-text-inverse);
    font-weight: var(--font-weight-bold);
}

.qabar__link:focus-visible {
    outline: var(--border-width-accent) solid var(--colour-surface);
    outline-offset: 2px;
}

/* The switch page itself: one calm column of four choices. */
.qa {
    max-width: 40rem;
    margin: 0 auto;
    padding: var(--space-lg) var(--layout-gutter);
}

.qa__heading {
    margin: 0 0 var(--space-2xs);
}

.qa__lede,
.qa__warning {
    color: var(--colour-text-muted);
}

.qa__list {
    display: grid;
    gap: var(--space-sm);
    margin: var(--space-md) 0;
    padding: 0;
    list-style: none;
}

.qa__item {
    padding: var(--space-sm);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-md);
}

.qa__item form {
    margin: 0;
}

.qa__button {
    width: 100%;
}

.qa__note {
    margin: var(--space-2xs) 0 0;
    font-size: var(--font-size-sm);
}

/* A word beside a name, for a fact that is not a link. Used for the captain marker: a badge
 * carrying TEXT rather than a colour, because the distinction has to survive without hue
 * (WCAG 2.2 AA, 1.4.1) and a coloured dot would not. */
.support__badge {
    display: inline-block;
    margin-left: var(--space-2xs);
    padding: 0 var(--space-2xs);
    background: var(--colour-surface-sunken);
    border-radius: var(--radius-sm);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    white-space: nowrap;
}

/* --- A long list of choices ------------------------------------------------------------------
 * Eighty-four countries, ten Novo areas, and names that do not fit on one line.
 *
 * IT REPLACED A <select multiple>, which could not wrap an option and cut "CxO Office (CEO
 * Office, Corporate Strategy, and Sustainability)" off mid-word at phone width. It is also the
 * control people operate worst — several selections need a modifier key, one stray click clears
 * them, and what is chosen disappears as the list scrolls.
 *
 * COLUMNS THAT COME AND GO WITH THE ROOM, and a capped height so a long list does not push the
 * form's action off the screen. The scroll is on the group rather than on the page, so the rest
 * of the form stays where it was. */
/* min() ON THE FLOOR, WHICH IS THE WHOLE FIX. auto-fill reduces the column COUNT as the box
 * narrows; it never shrinks the track's own minimum. So a bare minmax(22rem, 1fr) still demanded
 * 352px inside a column that is about 188px wide at 320px — two nested fieldsets each take 24px
 * of padding a side — and the region scrolled sideways to cover the difference. Because
 * overflow-y: auto makes the computed overflow-x auto too, the DOCUMENT stayed clean, which is
 * exactly why a page-level scroll check reported no problem and the long Novo area name was
 * still unreadable without scrolling. min(…, 100%) lets the track collapse to the room available.
 *
 * Caught by review; my own measurement missed it because Chrome's --window-size is not CSS
 * pixels here — a 320px window renders a 503px viewport, which had the room. */
.choices__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(14rem, 100%), 1fr));
    gap: var(--space-3xs) var(--space-md);
    /* Room for the focus ring, which is 3px wide at a 2px offset: without it the ring on the
     * first row and first column is clipped by this box's own overflow. */
    padding: var(--space-3xs);
    max-height: 18rem;
    overflow-y: auto;
    /* Positioned, so the focus ring of a checkbox scrolled to the edge is clipped by this box
     * rather than escaping it — the same containing-block rule the table scroller needed. */
    position: relative;
}

/* The Novo area names are long enough that two narrow columns would wrap every one of them. */
.choices__grid--wide {
    grid-template-columns: repeat(auto-fill, minmax(min(22rem, 100%), 1fr));
}

/* AN AUDIENCE LIST, FOLDED (QA-019).
 *
 * The country and EVP-area lists used to stand fully open and made "who receives this" the
 * largest thing on a screen whose job is writing a message. Each now sits in a native <details>:
 * the summary is one calm row stating the list's name and its current choice in words, and the
 * list opens beneath it. The group inside keeps its fieldset and hint for assistive technology
 * but drops its own frame, because the disclosure already draws one. */
.audience {
    margin: 0 0 var(--space-sm);
    border: var(--border-width) solid var(--colour-border);
    border-radius: var(--radius-md);
}

.audience__summary {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3xs) var(--space-sm);
    padding: var(--space-xs) var(--space-sm);
    cursor: pointer;
}

.audience__label {
    font-weight: var(--font-weight-bold);
}

.audience__state {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* THE CUE THAT THIS ROW OPENS. display:flex on <summary> removes the browser's own disclosure
 * marker, and design review found the rows then read as static statements — nothing said they
 * could be changed, and on a phone there is no hover cursor to hint. A chevron drawn in the text
 * colour, turned when open; the state words beside it already say what is chosen. */
.audience__state::after {
    content: '';
    width: 0.5em;
    height: 0.5em;
    border-right: 2px solid var(--colour-text);
    border-bottom: 2px solid var(--colour-text);
    transform: translateY(-25%) rotate(45deg);
}

.audience[open] .audience__state::after {
    transform: translateY(25%) rotate(-135deg);
}

.audience .admin__group {
    margin: 0;
    padding: 0 var(--space-sm) var(--space-sm);
    border: 0;
}

/* The label wraps; the box does not shrink with it. */
.choices__grid .field__choice span {
    min-width: 0;
}

/* A choice that cannot be changed.
 *
 * THE NATIVE SELECT GREYED ITSELF AND THE CHECKBOX LIST DID NOT. On a message that has left
 * draft, every box is disabled — and without this the labels rendered at full strength, so a
 * sealed audience looked editable and silently was not. Review found it. The tokens were already
 * defined and unused. */
.field__choice input:disabled + span {
    color: var(--colour-text-muted);
}

.field__choice input:disabled {
    cursor: not-allowed;
}

/* === MINE SKRIDT ==========================================================================
 *
 * The participant's own screen, built to the approved design at docs/design/final-mine-skridt.png.
 * Everything below consumes tokens from tokens.css: no hex, no font stack, no measurement
 * outside the scale. Where the reference and the design contract disagree, the contract wins —
 * the places that happens are named at the rules concerned.
 *
 * THE VISUAL LANGUAGE, IN ONE SENTENCE: white cards with generous radii floating on a pale Light
 * Blue field, a stronger tint marking every place a number is typed or read, one solid True Blue
 * action per panel, and the figure always larger than its own label.
 *
 * FOUR SURFACES, AND THE DIFFERENCE BETWEEN THEM IS THE POINT.
 *   - the app ground is the palest tint and carries nothing;
 *   - the hero sits on it and states context;
 *   - white cards hold the work;
 *   - a stronger tint inside a card marks a value — a field, a total, a badge.
 *
 * MOBILE-FIRST, like the rest of this stylesheet. The narrow layout is the base and the wide one
 * is the media query, because the phone is where the daily entry actually happens.
 */

/* The whole shell sits on the tint, and gets the room the design's proportions need. The page
 * itself is wider here than anywhere else in the product: --layout-measure is a readable line
 * length, and a seven-column grid inside it would be seven columns of four characters. */
/* The ground is the body's, warm, and the panels on it are the white — the wide shell used to
 * paint itself white, which is why Mine skridt and Stilling read as white pages with a warm strip
 * at the top rather than as cards on a ground. */
.shell--wide {
    background: var(--colour-surface-warm);
}

.shell--wide .page {
    max-width: 74rem;
    padding-bottom: var(--space-xl);
}

.pagestack {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

/* The band's field. Absolutely positioned so it fills the band edge to edge and the content
 * sits over it; the band's own overflow keeps it inside the rounded corners.
 *
 * THREE FLAT FILLS, one tint step apart. tokens.css records that the manual permits the whole
 * 0-100% range of a secondary colour's tints and asks for color-mix in the same form rather
 * than a pasted hex, which is what these are. Nothing here fades: what looks like depth is
 * three opaque colours meeting.
 */

/* THREE STEPS OF TWO PER CENT, not of three. The first attempt used 11/14/17 and the field read
 * as a solid bar with a hard edge across the illustration's feet rather than as water under it.
 * The reference's own waves are barely there; these are the same idea at the same strength. */

/* Hidden on a phone: at 390px the band is already three lines of fact under a display heading,
 * and a 340px illustration under them would push the first input off the screen. */

.panel {
    padding: var(--space-md);
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-xl);
    background: var(--colour-surface-raised);
    box-shadow: var(--shadow-sm);
}

/* A section's own mark, at the size the approved design sets it. */
.panel__icon {
    flex: 0 0 auto;
    width: 2.5rem;
    height: 2.5rem;
}

.panel__icon--wide {
    width: 2.75rem;
    height: auto;
}

/* A LINK ROW, the diploma under the standings: v4 draws no side stripes (Kenneth, 4/10), so it is
 * a plain line at the page's left edge rather than a card with a blue stripe. */
.pagestack__note {
    margin: 0;
    padding: var(--space-2xs) 0;
    color: var(--colour-text);
}

/* --- Dagens skridt ------------------------------------------------------------------------ */
.panel__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2xs) var(--space-sm);
    margin-bottom: var(--space-xs);
}

.panel__naming {
    flex: 1 1 auto;
    min-width: 0;
}

.panel__title {
    margin: 0;
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
    color: var(--colour-text);
}

.panel__lede {
    flex: 1 1 100%;
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-sm);
}

/* --- Konverter aktivitet --------------------------------------------------------------------
 *
 * A FLAT LIGHT-BLUE BAND, NOT A SECOND PANEL. The approved reference draws one tinted strip
 * inside the day's card: a title, one row of controls, an `=`, the answer and the button that
 * adds it. The previous version had a large icon, a heading at --font-size-xl, a full-width pale
 * button and a two-sentence footnote, and read as a second feature competing with the entry it
 * exists to serve. It is subordinate, so it looks subordinate.
 *
 * NOTHING FOLDS. It was briefly a <details> to match the reference's chevron, and an existing
 * guard refuses that: the calculator may never be behind a tap, in any state. So this is a plain
 * band with a quiet heading, always open.
 */
.converter {
    margin-top: var(--space-sm);
    padding: var(--space-sm) var(--space-md) var(--space-md);
    border-radius: var(--radius-lg);
    background: var(--colour-surface-field);
}

.converter__title {
    color: var(--colour-text);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
}

.converter__hint {
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* ONE ROW ON A LAPTOP. Controls take the space they need and the answer sits at the end, which
 * is the reference's composition: activity is the widest because its labels are the longest,
 * duration is narrow because it holds two digits. */
/* ONE ROW ON A LAPTOP, WRAPPING HONESTLY BELOW IT.
 *
 * FLEX RATHER THAN GRID, and that was a correction. A five-column grid put the button on a second
 * row at the left margin the moment the columns did not quite fit — a rigid track list cannot
 * reflow, it can only overflow or wrap one item. Flex lets each control ask for the width its
 * content needs, keeps the answer and the button together at the end, and folds to one column on
 * a phone without a second set of rules. */
.converter__row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-sm);
    margin-top: var(--space-sm);
}

.converter__row .field {
    flex: 1 1 100%;
    margin-bottom: 0;
    min-width: 0;
}

.converter__row .field__label {
    margin-bottom: var(--space-3xs);
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular);
}

.converter__result {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    margin: 0;
}

/* NO BOX: "Svaret er ikke et felt, så det har ingen ramme" (MySteps.dc.html). The label and the
 * figure stand on the band itself (F-050). */
.converter__result-body {
    display: flex;
    flex-direction: column;
    gap: 0;
    min-width: 0;
}

/* The equals sign the approved design sets between the controls and the answer. A character,
 * not a glyph — the font already has it, so it needs no asset and raises no brand question. */
.converter__equals {
    color: var(--colour-text-muted);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
}

/* THE ANSWER IS LABELLED LIKE THE FIELDS BESIDE IT, not like a caption. The board sets this at
 * 13px bold in ink — the same treatment "Aktivitet", "Varighed" and "Intensitet" get, because it
 * is the fourth thing in the same row and reads as one band. Muted and regular, it looked like a
 * footnote under a number. */
.converter__result-label {
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

/* 42px, the board's figure, which is the largest thing on the band and is meant to be: it is the
 * answer the whole row exists to produce. --font-size-2xl is 28. */
.converter__result-value {
    color: var(--colour-primary);
    font-size: 42px;
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
    letter-spacing: -0.035em;
    font-variant-numeric: tabular-nums;
}

/* NOTHING CALCULATED YET. The placeholder is F-034's mark, the en dash, muted and at regular
 * weight. An em dash in the figure's bold read as a thick blue bar on staging (F-055), where it
 * is meant to read as "no figure yet". It keeps the figure's own size at every width — 42, 38 on
 * the tablet, 34 on the phone — so the answer's line does not jump when a number arrives (F-050).
 * The size is therefore not set here; the rule further down mutes it and drops the weight. */
.converter__result--empty .converter__result-value {
    color: var(--colour-text-muted);
}

/* BESIDE THE ANSWER, NOT UNDER THE ROW, AND NOT THE SAME SHAPE AS SAVE.
 *
 * This was a full-width filled button below 48rem, which put a dark full-width control directly
 * above the dark full-width "Save today's steps" — two identical shapes, one of which saves
 * nothing, and staging read them as the same action. MyStepsMobile.dc.html draws it beside the
 * converted figure, content width, over a hairline.
 *
 * THE HAIRLINE IS DRAWN BY `.converter__answer`, and this comment used to say the opposite. It
 * was a `border-top` on each of the two, which worked until the button became the outlined
 * secondary variant and its own 2px pill border WAS its border-top. The pair is wrapped now and
 * the wrapper carries the rule — see the phone query near the end of this sheet, and the comment
 * in steps/partials/converter.blade.php. The rules that said otherwise are deleted rather than
 * left to be read as the mechanism, and with them a live trap: that border was the warm paper
 * hairline, which tokens.css keeps off the converter's tint on purpose. */
.converter__result {
    flex: 1 1 auto;
}

@media (min-width: 48rem) {
    /* THE BAND'S PROPORTIONS ARE MySteps.dc.html's, IN PIXELS, BECAUSE THE BOARD IS IN PIXELS.
     *
     * The activity grows to fill the row; the duration is 132 with its unit inside; the question
     * is 180. It rendered as `0 1 7rem` and `1 1 12rem`, which made the duration about 60px wide
     * — a box for a three-digit number that could not show three digits — while the activity
     * select took everything else (F-013). These are not tokens: they are one band's measured
     * widths, and writing them as rem would only disguise where they came from. */
    .converter__row .converter__field {
        flex: 1 1 12rem;
    }

    .converter__row .converter__field--narrow {
        flex: 0 0 132px;
    }

    .converter__row .converter__field--qualifier {
        flex: 0 0 180px;
    }

    .converter__result {
        flex: 0 0 auto;
    }
}

/* The duration box and its unit, on one line. The unit is beside the control rather than inside
 * the label so the three labels in the row are of a length with each other. */
.field__withunit {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
}

.field__withunit .field__input {
    flex: 1 1 auto;
}

.field__unit {
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* A select styled as its sibling input, so the converter's row reads as one row of controls
 * rather than as three unrelated widgets.
 *
 * NO BORDER HERE EITHER. This rule declared one in --colour-border-soft, which is 1.26:1 and
 * cannot bound a control; it painted nothing only because `.field__input, .field__select`
 * carries the same specificity, comes later, and restates the whole shorthand. That is exactly
 * what the dead declaration below was condemned for, so it goes the same way rather than
 * waiting for some future rule to set a border-width between the two and make it visible. */
.field__select {
    display: block;
    width: 100%;
    min-height: var(--touch-target-min);
    padding: var(--space-2xs) var(--space-sm);
    border-radius: var(--radius-lg);
    background: var(--colour-surface);
    color: var(--colour-text);
    font-family: inherit;
    /* 1rem minimum: iOS Safari zooms the viewport when a focused control is below 16px. */
    font-size: var(--font-size-lg);
}

/* No border-color here. It named --colour-border-soft and painted nothing: `.converter
 * .field__input` below carried the same specificity, came later, and won — so a search for the
 * pale token found this line and not the one doing the work. Both are gone now, and the
 * duration's edge is settled where the wrapper is styled. Any other `.converter__row
 * .field__input` would take its colour from `.field__input, .field__select`. */
.converter__row .field__input {
    border-width: var(--border-width);
    border-radius: var(--radius-lg);
    font-size: var(--font-size-lg);
}

/* --- The two actions -----------------------------------------------------------------------
 * .button--wide: the approved design puts both saves across the full width of their panel, at a
 * height that makes them the largest thing on it. The base .button caps itself at a 12rem
 * minimum from 40rem up, which is right for an inline action and wrong for the action a panel
 * exists to offer.
 */
.button--wide {
    width: 100%;
    padding: var(--space-xs) var(--space-md);
    border-radius: var(--radius-lg);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
}

@media (min-width: 40rem) {
    .button--wide {
        width: 100%;
        min-width: 0;
    }
}

/* --- The grid's confirmation page ---------------------------------------------------------- */
.confirm__days {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
    margin: 0 0 var(--space-md);
    padding: 0;
    list-style: none;
}

.confirm__day {
    padding: var(--space-sm);
    border: var(--border-width-strong) solid var(--colour-border-strong);
    border-radius: var(--radius-lg);
}

/* The days that are only coming along for the ride. Quieter, so the question is visibly about
 * the others — but present, because answering must not silently discard them. */
.confirm__day--quiet {
    border-width: var(--border-width);
    border-color: var(--colour-border-soft);
}

.confirm__day-date {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.confirm__day-total {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
}

.confirm__day-split {
    margin: var(--space-3xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.confirm__why {
    margin: 0 0 var(--space-md);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* --- Wider than a phone ------------------------------------------------------------------- */
@media (min-width: 40rem) {
    .converter__row {
        grid-template-columns: 1fr 1fr;
        gap: var(--space-sm);
    }
}

@media (min-width: 64rem) {
    .pagestack {
        gap: var(--space-sm);
    }

    /* The illustration, at the proportion the reference sets it: a little under a third of the
     * band, bled to its right edge. */

    .panel {
        padding: var(--space-sm) var(--space-md) var(--space-md);
    }

    .panel__icon {
        width: 3rem;
        height: 3rem;
    }

    .panel__icon--wide {
        width: 3.25rem;
    }

    .panel__title,
.converter__title {
        font-size: var(--font-size-2xl);
    }

    /* The converter's three controls and its answer, on one line. The answer takes the width it
     * needs and the controls share the rest, so a long activity name does not squeeze the number
     * the participant came for. */
    .converter__row {
        grid-template-columns: 1.2fr 0.8fr 1.2fr minmax(9rem, 0.9fr);
        align-items: end;
    }

    /* The answer is separated by a rule rather than by a gap: it belongs to the three controls
     * beside it, and a gap would make it a fourth one. */
    .converter__result {
        padding-left: var(--space-md);
        border-left: var(--border-width) solid var(--colour-border-soft);
        min-height: var(--touch-target-min);
    }

    .converter__result-value {
        font-size: var(--font-size-2xl);
    }
}

/* --- The application bar -------------------------------------------------------------------
 * The mark, the destinations and the way out, on one row.
 *
 * The approved Mine skridt design sets the brand on the left of the navigation rather than
 * centred above it. That is a composition change and not a brand change: the mark is still the
 * endorsing novohealth wordmark in the footer beside the product's name, for the reasons recorded
 * in layouts/public.blade.php. A Novo Nordisk logotype in this position would be the product
 * claiming Novo operates it, which is not the arrangement.
 */
.topbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-xs) var(--space-lg);
    margin-bottom: var(--space-md);
    padding-bottom: var(--space-2xs);
    border-bottom: var(--border-width) solid var(--colour-border-soft);
}

.topbar .gatemark {
    margin: 0;
    flex: 0 0 auto;
}

/* The bar loses its own rule and margin inside the topbar: one row, one separator. */
.topbar .bar {
    flex: 1 1 auto;
    margin-bottom: 0;
    padding-bottom: 0;
    border-bottom: 0;
    font-size: var(--font-size-base);
}

/* The way out sits at the far end, as the approved design places it. */
.topbar .bar__out {
    margin-left: auto;
}

/* --- The footer ------------------------------------------------------------------------------
 * The name and the novohealth mark on one side; the language choice on the other.
 */
.page__footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm) var(--space-lg);
}

/* THE NAME IN THE FOOTER, at the size a footnote is. It is the product's own name, so it is the
 * mark; it is a footer, so it is quiet. The novohealth wordmark sits beside it
 * (partials/novohealth-mark; the 2026 boards). */
/* --- Mine oplysninger, in two surfaces (QA-015) -----------------------------------------------
 *
 * It was one card across the whole content width, and staging QA read it as it looked: "too wide
 * and flat… reads like one large generic form". A form that wide also reads badly for its own
 * reason — a name field four hundred pixels longer than any name.
 *
 * THE DANGLING SELECTOR IS PART OF THE STORY. `.details-panel` used to carry a max-width, and an
 * edit left it grouped onto the rule below with its declarations gone, so the constraint its own
 * comment described had silently stopped applying. The measure is back, on a grid that also
 * gives the address a surface of its own.
 *
 * ORDER IS HIERARCHY. The two answers a participant can change come first; the address that
 * signs them in is second, and stays second when the columns stack on a phone.
 */
.profilework {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-md);
    align-items: start;
}

@media (min-width: 64rem) {
    .profilework {
        grid-template-columns: minmax(0, 1.6fr) minmax(18rem, 1fr);
    }
}

/* AT THE BOARD'S OWN CANVAS THE SIDEBAR IS A FIXED 440, not a share of the width.
 * MyDetails.dc.html draws `minmax(0, 1fr) 440px`, and a proportional second column put the
 * address card fifty pixels wider than drawn while taking them off the form beside it.
 *
 * THE FIRST TRACK STAYS FLUID, AND IT IS NOT A STYLE PREFERENCE.
 *
 * A second rule once restated this as `848px 440px` — the split the board RENDERS at its 1440
 * canvas — and that is the number you will be tempted by when you compare this screen against
 * MyDetails.dc.html at 1440 and find 833. Do not write it. 848 + 440 + 24 is 1312, which with
 * this page's two 64px gutters needs a 1440px page, and a 1440px WINDOW is not a 1440px page:
 * a classic scrollbar leaves 1425. `.page` is a flex item in `body.shell--wide`'s column, so
 * `min-width: auto` gives it a content-based minimum — it does not shrink, it overflows. With
 * the fixed tracks in place the body measured 1265 and `.page` measured 1440 inside it, and the
 * whole screen scrolled sideways at every width from 1280 to about 1455. Both numbers measured,
 * in the same page load, with and without the rule.
 *
 * The fluid track PRODUCES the board's 848 wherever the page really is 1440 wide: 1312 − 440 −
 * 24. It is the board's own declaration, character for character, and it gives back the fifteen
 * pixels the scrollbar takes instead of scrolling the page. See the invitations table further
 * down for the same fifteen pixels in the other direction.
 */
@media (min-width: 80rem) {
    .profilework {
        grid-template-columns: minmax(0, 1fr) 440px;
        gap: 24px;
    }
}

/* A fact the page already knows, not a control — so it is given room to break, because an
 * address is long and a column is narrow. The board sets it at the size of the card's own answer
 * rather than at body size: it is the card's subject, not a note in it. */
.emailcard__value {
    margin: var(--space-xs) 0 0;
    color: var(--colour-text);
    font-size: 22px;
    font-weight: var(--font-weight-bold);
    line-height: 1.25;
    overflow-wrap: anywhere;
}

.page__footer-brand {
    margin: 0;
    color: var(--colour-primary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
}

/* STEP COUNT in the editorial footer, matching the participant shell's treatment. */
.publicfoot__brand {
    margin: 0;
    color: var(--colour-primary);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
}

.page__footer .page__operator {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
}

.page__footer .language {
    margin: 0;
}

/* --- A wide desktop ---------------------------------------------------------------------------
 * Above the laptop breakpoint the grid's cells stop being the constraint, so the values go back
 * to their natural size and the hero takes the room the approved design gives it at that width.
 */
@media (min-width: 80rem) {
    /* THE SAME DESIGN, MORE ROOM — not a larger one. The reference is drawn at 1024, and its
     * type sizes are the design's sizes. What a wider window should buy is a wider content
     * column, not bigger numbers: at 74rem a 1440px window put 128px of empty tint down each
     * side and left the cards looking thin against it. The reference's own gutter is about four
     * per cent of the page, which is what this is. */
    .shell--wide .page {
        max-width: 82rem;
    }

    /* A WIDE WINDOW BUYS THE BAND DEPTH, NOT THE PAGE A BIGGER TYPE SCALE. The reference is an
     * artboard at 1024 and its sizes are the design's sizes; what a 1440px window should give
     * back is room, so the hero grows in the one dimension a wider page otherwise flattens. */

    .panel {
        padding: var(--space-md) var(--space-lg) var(--space-lg);
    }

    .converter__row {
        gap: var(--space-md);
    }
}

/* === MIT HOLD =============================================================================
 *
 * The captain's team page, built to the approved design and — this is the point — out of the
 * SAME parts as Mine skridt. The ground, the hero band, the card row, the panel and the button
 * geometry are not reimplemented here; they are the rules above, used again. What this section
 * adds is the three things Mit hold has and Mine skridt does not: a roster table, an invitation
 * panel, and a deadline that changes tense.
 *
 * ONE PANEL HEAD FOR BOTH SCREENS. `.panel__head` and its children are grouped with the
 * step page's own heads rather than copied, so the two pages cannot drift into two headings.
 */

/* --- The work area -------------------------------------------------------------------------
 * The roster is the primary content and takes the room; what the captain can do about it sits
 * beside it on a desktop. Stacked is the base, because the phone is where this is read on the
 * way to a meeting.
 *
 * THE ROSTER LEADS AT EVERY WIDTH, AND THAT IS SETTLED (ACC-005b item 6). It is worth keeping
 * why, because the obvious repair is the wrong one and somebody will reach for it again.
 *
 * `MobileFamily.dc.html` used to draw "Inviter en kollega" and "Kopiér holdlinket" directly
 * under the figures card, captioned "Both ways in are thumb-height above the roster". It was
 * tried with `order: -1` on the aside and taken back out: `order` moves the paint and not the
 * tab sequence, so driven at 390 the panel rendered above the roster while the keyboard still
 * reached the roster's eight invitation actions first — a reading order and a focus order that
 * disagree, which is WCAG 2.4.3. Putting the aside first in the markup instead only moves the
 * same mismatch onto the desktop.
 *
 * Neither could be satisfied by a declaration, so under CLAUDE.md section 11 the conflict was
 * surfaced rather than quietly picked, and the board moved: the phone board was redrawn with the
 * roster above the two ways in. So THERE IS NO CONFLICT LEFT HERE — the markup order and the
 * board now agree, and no `order` property is needed or wanted anywhere in this screen.
 */
.teamwork {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.teamwork__main,
.teamwork__aside {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    min-width: 0;
}

/* --- The roster ------------------------------------------------------------------------------
 * A real table: a name, a state and a date, read down as much as across.
 */
.roster-panel {
    padding-bottom: var(--space-xs);
}

/* `table-layout: fixed` would divide the width evenly and cut the addresses; auto layout with a
 * floor on the name column and a shrink-to-fit action column distributes it the way the approved
 * design does. `max-width` is the guarantee that nothing here can widen the panel it sits in. */
.roster-table {
    width: 100%;
    max-width: 100%;
    border-collapse: collapse;
    font-size: var(--font-size-sm);
}

.roster-table th {
    padding: var(--space-2xs) var(--space-xs);
    background: var(--colour-surface-field);
    color: var(--colour-text);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    text-align: left;
    white-space: nowrap;
}

.roster-table thead tr th:first-child {
    border-start-start-radius: var(--radius-lg);
    border-end-start-radius: var(--radius-lg);
}

.roster-table thead tr th:last-child {
    border-start-end-radius: var(--radius-lg);
    border-end-end-radius: var(--radius-lg);
}

.roster-table td {
    padding: var(--space-2xs) var(--space-xs);
    border-bottom: var(--border-width) solid var(--colour-surface-field);
    color: var(--colour-text);
    vertical-align: middle;
}

.roster-table tbody tr:last-child td {
    border-bottom: 0;
}

.roster-table__number {
    width: 2.5rem;
    color: var(--colour-text);
    font-weight: var(--font-weight-medium);
}

.roster-table__name {
    font-weight: var(--font-weight-medium);
}

/* AN ADDRESS IS NOT A NAME. Colleagues' names are short and should never break; an invited
 * address is long, and holding it on one line pushed the action column off the panel.
 *
 * `anywhere` BROKE IT MID-DOMAIN — "louise.kristensen@novonordi / sk.com" — which reads as a
 * rendering fault rather than as a wrapped address. `break-word` breaks between words where it
 * can and only splits a run that genuinely cannot fit, so the local part and the domain stay
 * whole at every width this table is used at. The column is given room to make that possible
 * rather than left to fight the action buttons for it. */
.roster-table__person {
    word-break: break-word;
}

/* A SHARE OF THE TABLE — ON A TABLE.
 *
 * min-width on a <td> is advisory under table-layout:auto and the browser ignored it, so the
 * address kept being squeezed to about 200px and broke inside the domain. A percentage is a
 * constraint the algorithm honours.
 *
 * ONLY WHERE THERE IS STILL A TABLE, though. On a phone the roster stacks into rows, and 34% of
 * a 350px card is 120px — which broke "Line Sørensen" across two lines and an address across
 * seven. Found in the phone screenshot. */
@media (min-width: 48rem) {
    .roster-table__name {
        width: 38%;
    }

    /* AN ADDRESS IS SECONDARY TO A NAME, and setting it a step smaller is what finally let
     * "louise.kristensen@novonordisk.com" sit on one line in the column it has. At body size it
     * overran by a few pixels and broke inside the domain — which reads as a rendering fault
     * rather than as a long address. The rows that hold names are untouched. */
    .roster-table__row--invited .roster-table__person,
    .roster-table__row--expired .roster-table__person {
        font-size: var(--font-size-sm);
    }
}

/* The captain, named in the row rather than inferred from position one. */
.roster-table__badge {
    display: inline-block;
    margin-left: var(--space-2xs);
    padding: 0 var(--space-2xs);
    border-radius: var(--radius-pill);
    background: var(--colour-surface-badge);
    color: var(--colour-text);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
    white-space: nowrap;
}

.roster-table__status {
    white-space: nowrap;
}

/* The dot agrees with the word beside it and carries nothing on its own. */
.roster-table__dot {
    display: inline-block;
    width: 0.625rem;
    height: 0.625rem;
    margin-right: var(--space-2xs);
    border-radius: var(--radius-pill);
    background: var(--nn-granite-grey);
    vertical-align: baseline;
}

/* The CELL stays a cell — `display: flex` on a <td> takes it out of the table's own layout, so
 * the buttons live in a box inside it instead. */
/* `width: 1%` is the table idiom for "as narrow as your content needs": auto layout gives a cell
 * its content width and shares what is left between the rest, so the two buttons are never the
 * thing that gets squeezed. */
.roster-table__action-cell {
    width: 1%;
    white-space: nowrap;
}

.roster-table__actions {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--space-2xs);
    align-items: center;
}

.roster-table__none {
    color: var(--colour-text-muted);
}

.roster-table__empty {
    margin: 0;
    padding: var(--space-md) 0;
    color: var(--colour-text-muted);
}

/* An outstanding invitation reads a shade quieter than a member: it is a person who has not
 * answered yet, and the row should not claim them. */
.roster-table__row--invited .roster-table__name,
.roster-table__row--expired .roster-table__name {
    font-weight: var(--font-weight-regular);
}

/* --- Inviting --------------------------------------------------------------------------------- */
.invite {
    margin: 0;
}

.invite__controls {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
    align-items: stretch;
}

.invite__input {
    border-width: var(--border-width);
    border-color: var(--colour-border-soft);
    border-radius: var(--radius-lg);
    font-size: var(--font-size-base);
}

.invite__submit {
    width: 100%;
    min-width: 0;
    border-radius: var(--radius-lg);
    font-weight: var(--font-weight-bold);
}

/* --- The second way in, beneath an "or" (QA-008) ----------------------------------------------
 * The approved design separates the email invite from the shared link with a rule and the word
 * "or". It is one control, not a second panel: the captain is choosing how to invite, not
 * deciding between two features.
 */
.invite__alt {
    margin-top: var(--space-sm);
}

/* A rule with the word sitting in it. The pseudo-elements draw the two halves, so the word does
 * not need a background matching whatever is behind the card. */
.invite__or {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    margin: 0 0 var(--space-sm);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.invite__or::before,
.invite__or::after {
    content: '';
    flex: 1 1 auto;
    height: var(--border-width);
    background: var(--colour-border-soft);
}

/* THE LINK IS LONG AND MUST NOT WRAP INTO SOMETHING UNSELECTABLE. A monospace face makes a
 * random hex code readable character by character, which matters when somebody is checking they
 * pasted the right one. */
.invite__link {
    width: 100%;
    border-width: var(--border-width);
    border-color: var(--colour-border-soft);
    border-radius: var(--radius-lg);
    background: var(--colour-surface-field);
    color: var(--colour-text);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: var(--font-size-sm);
    text-overflow: ellipsis;
}

.invite__link-note {
    margin: var(--space-2xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

/* --- A note beside an icon -------------------------------------------------------------------
 * Used for the invitation rules and for what is still true after the deadline. The tint is the
 * one the rest of the product uses for "a value, or a fact about one".
 */
.notecard {
    display: flex;
    align-items: flex-start;
    gap: var(--space-xs);
    margin-top: var(--space-sm);
    padding: var(--space-xs) var(--space-sm);
    border-radius: var(--radius-lg);
    background: var(--colour-surface-field);
}

.notecard__icon {
    flex: 0 0 auto;
    width: 1.5rem;
    height: 1.5rem;
}

.notecard__body {
    min-width: 0;
}

.notecard__line {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

.notecard__line + .notecard__line {
    margin-top: var(--space-3xs);
}

/* --- Closed ------------------------------------------------------------------------------------ */
.closed-panel__line {
    margin: 0 0 var(--space-2xs);
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

/* --- The deadline ------------------------------------------------------------------------------
 * A date, not a countdown: the hero already says how many days are left, and these two answer
 * different questions.
 */
.deadline-panel {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}

.deadline-panel__body {
    min-width: 0;
}

.deadline-panel__date {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
}

.deadline-panel__note {
    margin: var(--space-3xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* --- Wider than a phone -------------------------------------------------------------------- */
@media (min-width: 64rem) {
    /* THE ROSTER TAKES THE ROOM. The approved design gives it about two thirds and the captain's
     * controls the rest — which is the right way round, because the list is what the page is
     * for and the panel beside it is one field and one button. */
    .teamwork {
        display: grid;
        grid-template-columns: minmax(0, 1.85fr) minmax(23rem, 1fr);
        gap: var(--space-sm);
        align-items: start;
    }
}

/* THE PAGE IS TWO COLUMNS FROM A LAPTOP; THE TABLE IS FIVE FROM A WIDE ONE.
 *
 * At 1024 the roster column is about 640px, which is not enough for a number, a name, a status,
 * a date and two buttons — they ran off the panel. The page keeps its two columns there, because
 * the invitation panel beside the list is right at that width; the list inside it keeps the
 * stacked rows until there is genuinely room for five.
 */

@media (min-width: 80rem) {
    .roster-table {
        font-size: var(--font-size-base);
    }

    .roster-table th,
    .roster-table td {
        padding: var(--space-2xs) var(--space-xs);
    }

    .roster-table th {
        font-size: var(--font-size-sm);
    }

    /* THE NAME COLUMN GETS A FLOOR, AND ONLY A FLOOR.
     *
     * Without one, `width: 1%` on the action cell let auto layout squeeze names until the
     * captain's badge wrapped under his own name. With too generous a one, five columns of
     * nowrap content came to more than the grid column and the two buttons ran off the panel.
     * Twelve rems holds every colleague name on one line and lets an invited address — which is
     * three times longer and is the only identifier an unaccepted invitation has — wrap instead
     * of pushing the actions out of view. */
    .roster-table__name {
        min-width: 14rem;
    }

    /* A COLLEAGUE'S NAME NEVER BREAKS; AN ADDRESS MAY.
     *
     * A member row is a person and their role, and letting it wrap put the captain's badge on a
     * line under his own name — which reads as a second fact about him rather than as a label on
     * the first. An invitation row has no name to show: until somebody accepts, the only
     * identifier the product holds is the address they were written to, and an address is three
     * times longer than a name. So that one wraps, and the actions beside it keep their room. */
    .roster-table__row--member .roster-table__name {
        white-space: nowrap;
    }
}

@media (min-width: 64rem) {
    /* The field and its button on one line, as the approved design sets them. */
    .invite__controls {
        flex-direction: row;
        align-items: stretch;
    }

    .invite__input {
        flex: 1 1 auto;
        min-width: 0;
    }

    .invite__submit {
        flex: 0 0 auto;
        width: auto;
        padding-inline: var(--space-sm);
    }
}

/* --- Narrower than a laptop ---------------------------------------------------------------------
 * ONE COLUMN, AND THE TABLE STAYS A TABLE. The approved mobile design keeps the roster as rows
 * rather than turning it into cards, so the columns stay associated and a screen reader can
 * still say "Status: Invitation sendt". What gives way instead is the padding, the type step and
 * the action buttons, which stack.
 */
@media (max-width: 79.999rem) {
    .roster-panel {
        padding-inline: var(--space-sm);
    }

    /*
     * THE ROW BECOMES TWO LINES, AND THAT IS THE ONE PLACE THIS SCREEN LEAVES THE APPROVED
     * MOBILE COMP.
     *
     * The comp fits five columns and two buttons across a phone by setting the table at about
     * eleven pixels. That is achievable and it costs the thing this product does not trade: a
     * button at that size is nowhere near the 44px target the rest of the product holds itself
     * to, and the requirement for this page says touch targets stay accessible in the same
     * breath as it says to follow the comp.
     *
     * So the data stays on one line and the actions take their own, at full size. Nothing is
     * dropped — name, role, status, activity and both actions are all still there, and the
     * association between a row and its buttons is stronger than it was, because they are inside
     * the row rather than at the far end of it.
     *
     * THE TABLE IS STILL A TABLE. `display: grid` on a <tr> would otherwise take the whole thing
     * out of the accessibility tree; the explicit role attributes in the partial are what keep a
     * screen reader saying "Status: Invitation sendt" while the eye sees two lines.
     */
    .roster-table,
    .roster-table thead,
    .roster-table tbody,
    .roster-table__row {
        display: block;
    }

    /* The header row goes, because the row beneath it is no longer a row of columns. The two
     * cells that are not self-describing carry their own label instead. */
    .roster-table thead {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .roster-table__row {
        display: grid;
        grid-template-columns: 1.5rem minmax(0, 1fr) auto;
        align-items: baseline;
        gap: var(--space-3xs) var(--space-2xs);
        padding: var(--space-xs) 0;
        border-bottom: var(--border-width) solid var(--colour-surface-field);
    }

    .roster-table tbody tr:last-child {
        border-bottom: 0;
    }

    .roster-table td {
        display: block;
        padding: 0;
        border-bottom: 0;
    }

    .roster-table__number {
        grid-column: 1;
        grid-row: 1;
        width: auto;
        color: var(--colour-text-muted);
    }

    .roster-table__name {
        grid-column: 2;
        grid-row: 1;
        min-width: 0;
    }

    .roster-table__status {
        grid-column: 3;
        grid-row: 1;
        text-align: right;
    }

    .roster-table__action-cell {
        grid-column: 1 / -1;
        width: auto;
        white-space: normal;
    }

    /* AN EM DASH ON ITS OWN LINE UNDER A MEMBER IS A LINE ABOUT NOTHING, so that cell goes.
     *
     * ON THE CELL'S OWN MODIFIER, NOT ON THE ROW, AND THE DIFFERENCE WAS A BUG. This read
     * `.roster-table__row--member .roster-table__action-cell`, which was right while the cell
     * could only ever hold a dash. ACC-010 put Remove and Make captain in it, and the rule went
     * on hiding the whole cell — so at 390 a captain had two controls rendered at 0x0 and no way
     * to remove or promote anybody from a phone. Driven, not read: the markup was correct and
     * the stylesheet was deleting it.
     *
     * The template sets `--empty` when the cell holds only the dash, which is the captain's own
     * row and every row once sign-ups have closed. */
    .roster-table__action-cell--empty {
        display: none;
    }

    .roster-table th,
    .roster-table td {
        padding: var(--space-2xs) var(--space-3xs);
    }

    .roster-table__number {
        width: 1.5rem;
    }

    .roster-table__badge {
        margin-left: 0;
        margin-top: var(--space-3xs);
        display: inline-block;
    }

    /* The name and its badge stack, so a long name does not push the status column off. */
    .roster-table__name {
        white-space: normal;
    }

    .roster-table__person {
        white-space: normal;
    }

    /* Two small buttons on top of each other rather than side by side: at this width they would
     * otherwise take more room than the three columns before them. */
    .roster-table__action-cell {
        white-space: normal;
    }

    .roster-table__actions {
        flex-direction: row;
        flex-wrap: wrap;
        align-items: stretch;
        margin-top: var(--space-2xs);
    }

    /* THE FORM IS A WRAPPER, NOT A LAYOUT PARTICIPANT. As a growing flex item it pushed "Send a
     * reminder" and "Delete" to opposite ends of the invitation row while the member row's two
     * pills stayed side by side — two families of the same control, laid out two ways, on
     * adjacent tables. The board draws both pairs adjacent. */
    .roster-table__actions form {
        flex: 0 0 auto;
    }
}

/* --- Who is signed in -------------------------------------------------------------------------
 * A statement in the bar, not a menu. The approved designs put the person's name and their role
 * beside the way out; everything about an account lives under Mine oplysninger, and a dropdown
 * here would be a second route to it to keep in step with the first.
 */
.whoami {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    margin: 0 0 0 auto;
    padding-right: var(--space-sm);
    border-right: var(--border-width) solid var(--colour-border-soft);
}

.whoami__initials {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: var(--radius-pill);
    background: var(--colour-primary);
    color: var(--colour-text-on-primary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
}

.whoami__body {
    display: flex;
    flex-direction: column;
    line-height: var(--line-height-tight);
}

.whoami__name {
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.whoami__role {
    color: var(--colour-accent-on-surface);
    font-size: var(--font-size-xs);
}

/* The way out keeps its place at the very end; the name sits before it. */
.topbar .bar__out {
    margin-left: var(--space-sm);
}

/* The nav takes the slack so the person and the way out stay right-aligned. */
.topbar .bar {
    flex: 1 1 auto;
}

/* At phone width the bar already wraps to two rows; the name goes with the brand rather than
 * squeezing the destinations. */
/* On a phone the bar is two rows, and the approved design puts the brand and the person on the
 * first with the destinations beneath. `order` does it without a second copy of the markup. */
@media (max-width: 47.999rem) {
    .topbar {
        flex-wrap: wrap;
        gap: var(--space-2xs) var(--space-sm);
    }

    /* The person's mark shrinks so the brand, the person and the way out share the first line
     * the way the approved design has them, leaving the second for the destinations. */
    .whoami__initials {
        width: 1.9rem;
        height: 1.9rem;
        font-size: var(--font-size-xs);
    }

    .whoami__name {
        font-size: var(--font-size-xs);
    }

    .whoami__role {
        font-size: var(--font-size-xs);
    }

    /* Five destinations on one row at this width need the smaller step; at the base size they
     * wrap onto a third line and the bar costs more of the screen than the panel below it. */
    .topbar .bar {
        font-size: var(--font-size-sm);
        gap: var(--space-2xs);
    }

    /* STEP COUNT FIRST, MENU LAST — the approved mobile header, in that order.
     *
     * `order: 1` was set when the phone bar was brand-then-person-then-links wrapped over rows,
     * and it survived the hamburger: the button, declared after the mark but carrying
     * margin-left:auto, ended up left of a mark that had been ordered behind it. The header read
     * "[menu] STEP COUNT", both shoved right. Source order is now the right order. */
    .topbar .gatemark {
        order: 0;
        margin-right: auto;
    }

        .whoami {
        order: 2;
        margin-left: auto;
        padding-right: var(--space-xs);
    }

    .topbar .bar__out {
        order: 3;
        margin-left: 0;
    }

    .topbar .bar {
        order: 4;
        flex: 1 1 100%;
    }
}

/* === MINE OPLYSNINGER ======================================================================
 *
 * A form beside two statements, on the same shell as Mine skridt and Mit hold. Everything
 * structural here already existed — the ground, the band, the panel, the button geometry. What
 * this section adds is the three things this page has and the others do not: a form laid out in
 * a card, an address shown as a fact, and a route to somebody who can change it.
 */
/* --- The form ------------------------------------------------------------------------------
 * The fields are partials.profile-fields, shared with onboarding, so the labels and hints are
 * not restyled here — only the box they sit in and the button that submits them.
 */
.profileform .field {
    margin-bottom: var(--space-sm);
}

.profileform .field__label,
.profileform .gate__label {
    color: var(--colour-text);
    font-weight: var(--font-weight-bold);
}

/* NOTHING SCOPED TO `.profileform` ANY MORE, and that is the whole of it.
 *
 * It carried the field edge to these two controls by hand, because `select.field__input`
 * outranked the rule that should have given it to them — see the note on that list above. With
 * the qualifier gone they inherit it. What was left after the border came out was a
 * `border-radius` that painted nothing either: `.details-panel .field__input, .details-panel
 * .field__select` sets the radius at the same specificity and later in source, and this form is
 * only ever rendered inside that panel. Confirmed by asking the browser which rules matched.
 *
 * Kept as a comment rather than an empty rule, because a rule that restates what a control
 * already has is a place for the two to disagree later — which is the argument this change is
 * made of. `.placeform .gate__select` once kept an 8px radius on Mit hold; item 12 of the component
 * sheet (2026-10-04) gives every select the one 12px box, so it went too. F-045, second half. */

/* NO TINT ON THIS SCREEN, and the gate's own rule explains why. It tints the fieldset to avoid
 * "a third container inside the second one" — on the gate there are two: an outlined box inside
 * a white card. Here there are already three grounds before the fieldset starts (the page tint,
 * the white card, the tinted fields), so the tint that removes a layer there adds one here: it
 * rendered as a second card inside the first, which is exactly the layering the approved design
 * does not have and the design contract section 1 asks to avoid. The legend and the sentence
 * under it still group the two questions; they no longer need a box to do it. */
.profileform .gate__group {
    margin: 0;
    padding: 0;
    background: none;
}

/* The legend carries the grouping on its own, so it is sized like the thing it is — a heading
 * over two fields — rather than like a label. */
.profileform .gate__legend {
    margin-bottom: var(--space-3xs);
    font-size: var(--font-size-base);
}

.profileform .gate__note {
    margin-bottom: var(--space-sm);
}

.profileform__note {
    margin: 0 0 var(--space-sm);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

/* --- The address ----------------------------------------------------------------------------
 * A read-only box rather than a disabled input, and the difference is what it says: "this is
 * what we know" rather than "you may not touch this". A greyed-out field invites somebody to
 * try, and then to wonder what they did wrong.
 */
.email-panel__address {
    margin: 0;
    padding: var(--space-xs) var(--space-sm);
    border-radius: var(--radius-lg);
    background: var(--colour-surface-field);
    color: var(--colour-text);
    font-size: var(--font-size-lg);
    overflow-wrap: anywhere;
}

/* --- Support --------------------------------------------------------------------------------- */
/* --- Wider than a laptop ---------------------------------------------------------------------
 * The form takes the room and the two statements sit beside it, which is the proportion the
 * approved design sets. Stacked below that, because the phone is where a correction gets made
 * on the way to something else.
 */
/* THE TWO-COLUMN RULE WENT WITH THE SECOND COLUMN. Mine oplysninger was a form beside a card for
 * the address and a card for support; both are folded in now, so there is one column and it is
 * constrained to a readable measure rather than to a grid track. */

/* === KONKURRENCER ==========================================================================
 *
 * Three cards and a band, out of the same parts as the other three participant screens: the
 * ground, the wave field, the raised card, the chip, the panel head. What this section adds is
 * the two things Konkurrencer has and the others do not — a card inside the band, and a card
 * that reads left to right: what it is, how it works, and what state it is in.
 */

/* The campaign's two facts sit side by side under the lede rather than stacked in a column of
 * their own, because this band's third column is a card and there is no room for a fourth. */

/* --- A competition's state pill ------------------------------------------------------------------ */
/* THE STATE, AS A WORD ON A TINT. The dot is the accent and the word is the answer; neither
 * Golden Yellow nor Forest Green reaches 4.5:1 against white, so neither is ever the text. */
.competition__state {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2xs);
    margin: var(--space-xs) 0 0;
    padding: var(--space-3xs) var(--space-sm);
    border-radius: var(--radius-pill);
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

.competition__dot {
    flex: 0 0 auto;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: currentcolor;
}
/* --- The competitions: three this platform runs, and Novo's own fourth --------------------- */
.competition-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    margin: 0;
    padding: 0;
    list-style: none;
}

.competition {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    padding: var(--space-md);
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-xl);
    background: var(--colour-surface-raised);
    box-shadow: var(--shadow-sm);
}

.competition__icon {
    flex: 0 0 auto;
    width: 3.5rem;
    height: auto;
}

.competition__body {
    min-width: 0;
    flex: 1 1 auto;
}

.competition__name {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
}

.competition__rule {
    margin: var(--space-3xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-base);
    line-height: var(--line-height-base);
}

/* THE RULE, SAID IN PIECES. A rule of one sentence and a row of two or three short facts are
 * the same rule twice, and that is deliberate: the sentence is for somebody reading the page and
 * the row is for somebody scanning it. The divider is a border rather than a separate element,
 * so a row that wraps on a phone does not leave a rule hanging in the air. */
/* A COLUMN ON A PHONE AND A ROW ABOVE ONE, and the divider turns with it.
 *
 * The approved mobile design draws three facts side by side. Measured at 390px, ours will not go:
 * the Danish labels are longer than the comp's — "Alle skal registrere" against "Hele holdet" —
 * and three columns of about a hundred pixels broke "13. november 2026" over four lines. A fact
 * nobody can read is worse than a fact on its own line, so below 48rem they stack, and the rule
 * between them turns with them rather than being dropped.
 *
 * THE FIRST ATTEMPT WRAPPED INSTEAD, which is the version of this that looks right until you see
 * it: each wrapped item kept the left border that belonged between it and the item now above it,
 * so a vertical rule stood at the start of a line with nothing on its other side. */
.competition__facts {
    display: flex;
    flex-direction: column;
    gap: 0;
    margin: var(--space-sm) 0 0;
    padding: var(--space-sm) 0 0;
    border-top: var(--border-width) solid var(--colour-border-soft);
}

.competition__fact {
    min-width: 0;
    padding: var(--space-2xs) 0;
    border-top: var(--border-width) solid var(--colour-border-soft);
}

.competition__fact:first-child {
    padding-top: 0;
    border-top: 0;
}

/* Top-aligned, because a label of two lines beside a one-line icon should hang from the icon
 * rather than float level with the middle of itself. */
.competition__fact-label {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2xs);
    color: var(--colour-text);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-base);
}

.competition__fact-icon {
    flex: 0 0 auto;
    width: 1.15rem;
    height: auto;
}

/* Aligned under the label's text rather than under its icon, so the two lines read as one fact
 * with a heading and not as a list with a stray indent. */
.competition__fact-detail {
    margin: 0 0 0 calc(1.15rem + var(--space-2xs));
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    line-height: var(--line-height-base);
}

.competition__standing {
    margin-top: var(--space-sm);
}

.competition__standing-line {
    margin: 0 0 var(--space-3xs);
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

.competition__standing-line:last-child {
    margin-bottom: 0;
}

/* --- State and date --------------------------------------------------------------------------- */
.competition__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-xs) var(--space-md);
    margin: 0;
}

.competition__meta-item {
    min-width: 0;
}

.competition__state {
    margin-top: 0;
}

.competition__state--running {
    background: var(--board-positive-ground);
}

.competition__state--running .competition__dot {
    background: var(--colour-success);
}

.competition__state--not_started,
.competition__state--finished {
    background: var(--colour-surface-badge);
}

.competition__state--not_started .competition__dot,
.competition__state--finished .competition__dot {
    background: var(--colour-accent-on-surface);
}

.competition__when {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.competition__when-icon {
    flex: 0 0 auto;
    width: 1.35rem;
    height: auto;
}

/* --- Wider than a phone -----------------------------------------------------------------------
 * The chip moves beside the name, which is where the approved design has it at every width above
 * a phone.
 */
@media (min-width: 48rem) {
    .competition {
        flex-direction: row;
        align-items: flex-start;
    }

    .competition__icon {
        width: 4.5rem;
    }

    /* Side by side, as the reference draws them, with the rule between them standing up.
     *
     * NOWRAP, AND THE SHRINKING HAPPENS INSIDE A FACT INSTEAD. Allowed to wrap, a three-fact row
     * broke at 1024 and the item that moved to the second line took its left border with it —
     * a divider standing at the start of a row with nothing on its other side. Letting each fact
     * narrow and wrap its own words keeps the row a row at every width that has one, which is
     * also what the reference draws. */
    .competition__facts {
        flex-direction: row;
        flex-wrap: nowrap;
        gap: 0;
    }

    .competition__fact {
        flex: 0 1 auto;
        padding: 0 var(--space-sm);
        border-top: 0;
        border-left: var(--border-width) solid var(--colour-border-soft);
    }

    .competition__fact:first-child {
        padding-left: 0;
        border-left: 0;
    }

    .competition__fact-label {
        font-size: var(--font-size-sm);
    }

    .competition__fact-icon {
        width: 1.35rem;
    }

    .competition__fact-detail {
        margin-left: calc(1.35rem + var(--space-2xs));
        font-size: var(--font-size-sm);
    }
}

/* --- Wider than a laptop -----------------------------------------------------------------------
 * The card becomes what the reference draws: the competition on the left, its state and date in a
 * column of their own on the right, divided by a rule.
 */
@media (min-width: 64rem) {
    /* Side by side under the lede, divided, as the reference draws them. Nowrap on each keeps a
     * date whole; the band is measured below so that both fit on the one line. */

    .competition {
        align-items: center;
        gap: var(--space-md);
        padding: var(--space-md) var(--space-lg);
    }

    .competition__icon {
        width: 6.5rem;
    }

    /* NO RULE ABOVE THE FACTS AT THIS WIDTH, and there is one below it. On a phone the facts are
     * a block of their own under the sentence and the rule separates them; on a desktop they are
     * the same line continuing, and the reference draws no divider there. */
    .competition__facts {
        border-top: 0;
        padding-top: var(--space-2xs);
    }

    .competition__meta {
        flex: 0 0 auto;
        flex-direction: column;
        align-items: flex-start;
        width: 15rem;
        padding-left: var(--space-md);
        border-left: var(--border-width) solid var(--colour-border-soft);
    }
}

/* --- Wider than a laptop, again ----------------------------------------------------------------
 * The right-hand column takes the share the reference gives it. Held back until here because at
 * 1024 the same width left the three facts about 140px each and broke "13. november 2026" over
 * three lines — the column that states one date does not get to squeeze the ones that state the
 * rules.
 */
@media (min-width: 80rem) {
    .competition__meta {
        width: 19rem;
    }
}

/* === STILLING ==============================================================================
 *
 * Two boards under one band, out of the same parts as the other four participant screens. What
 * this section adds is the three things Stilling has and the others do not: a pair of tabs, a
 * pair of filter rows that are deliberately not equals, and a real table.
 */

/* --- The two boards --------------------------------------------------------------------------
 * A segmented control made of links. Each half is a real address; the current one is filled and
 * announced, and the pair sits on the page ground rather than inside the card, as the reference
 * draws it.
 */
.boardtabs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0;
    max-width: 28rem;
    border-radius: var(--radius-lg);
    background: var(--colour-surface-raised);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

.boardtabs__tab {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: var(--touch-target-min);
    padding: var(--space-2xs) var(--space-sm);
    color: var(--colour-accent-on-surface);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    text-align: center;
    text-decoration: none;
}

.boardtabs__tab--on {
    background: var(--colour-text);
    color: var(--colour-surface-raised);
}

/* --- The filters -----------------------------------------------------------------------------
 * Two rows on a tinted ground, the way the reference groups them. The first decides which
 * competition; the second decides how it is counted, and is drawn as the lesser of the two — see
 * the partial for why that is a product statement rather than a styling preference.
 */
.filters {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
    padding: var(--space-2xs);
    border-radius: var(--radius-lg);
    background: var(--colour-surface-app);
}

.filters__row {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: var(--space-2xs);
}

.filters__choice {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: var(--touch-target-min);
    padding: var(--space-3xs) var(--space-xs);
    border-radius: var(--radius-md);
    background: var(--colour-surface-raised);
    color: var(--colour-accent-on-surface);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    text-align: center;
    text-decoration: none;
}

.filters__choice--on {
    background: var(--colour-text);
    color: var(--colour-surface-raised);
}

/* THE SECONDARY ROW, AND THIS IS WHERE IT IS SAID IN CSS. Smaller type, lighter weight, a
 * shorter control and less contrast when it is off — so the eye reaches the scope first and reads
 * this as a setting on the board rather than as a fourth board. It is still a real control with a
 * full touch target; quieter is not the same as smaller to hit. */
.filters__row--secondary {
    grid-auto-columns: minmax(0, 0.8fr);
    justify-content: start;
}

.filters__choice.filters__choice--quiet {
    min-height: 2.25rem;
    padding: var(--space-3xs) var(--space-sm);
    background: none;
    border-color: transparent;
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
}

.filters__choice--quiet.filters__choice--on {
    font-weight: var(--font-weight-bold);
}

.filters__note {
    margin: 0;
    padding: var(--space-3xs) var(--space-2xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    line-height: var(--line-height-base);
}

/* --- The board itself --------------------------------------------------------------------------
 * A real table. Five columns of independent values, compared down as much as across — see the
 * partial for why this stopped being a list.
 */
.board-table__scroll {
    /* The one element on this screen allowed to scroll sideways, and only if a very long team
     * name forces it. The page body never does. */
    overflow-x: auto;
}

.board-table {
    width: 100%;
    max-width: 100%;
    border-collapse: collapse;
    font-size: var(--font-size-sm);
}

.board-table th {
    padding: var(--space-2xs) var(--space-xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    text-align: left;
    white-space: nowrap;
}

.board-table thead th {
    background: var(--colour-surface-field);
}

.board-table thead tr th:first-child {
    border-start-start-radius: var(--radius-lg);
    border-end-start-radius: var(--radius-lg);
}

.board-table thead tr th:last-child {
    border-start-end-radius: var(--radius-lg);
    border-end-end-radius: var(--radius-lg);
}

.board-table td {
    padding: var(--space-xs);
    border-bottom: var(--border-width) solid var(--colour-surface-field);
    color: var(--colour-text);
    vertical-align: middle;
}

.board-table tbody th {
    padding: var(--space-xs);
    border-bottom: var(--border-width) solid var(--colour-surface-field);
    background: none;
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

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

.board-table__rank {
    width: 4.5rem;
}

.board-table__name {
    font-weight: var(--font-weight-medium);
    overflow-wrap: anywhere;
}

.board-table__figure {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* THE READER'S OWN ROW. A tint, a weight and a word — and the word is in the markup, because a
 * row somebody cannot find is the one failure this table must not have. */
.board-table__row--you th,
.board-table__row--you td {
    background: var(--colour-surface-field);
    font-weight: var(--font-weight-bold);
}

.board-table__you {
    margin-left: var(--space-3xs);
    color: var(--colour-accent-on-surface);
    font-weight: var(--font-weight-medium);
}

/* NARROW ENOUGH THAT A COLUMN HAS TO GO. Which one differs by board and is decided in the
 * partial: the team board folds its member count and entry rate into a line under the name, and
 * the personal board drops the average, because that is what the approved mobile design does.
 * The cells are hidden rather than allowed to scroll out of sight — a column somebody has to
 * discover by dragging is a column they will not find. */
.board-table__wide {
    display: none;
}

/* The break where the board really does skip rows. Decorative and aria-hidden: the ranks either
 * side of it already say a jump happened, and "ellipsis" read aloud is noise. */
.board-table__gap td {
    padding: var(--space-3xs) var(--space-xs);
    border-bottom: var(--border-width) solid var(--colour-surface-field);
    color: var(--colour-text-muted);
    text-align: center;
    letter-spacing: 0.3em;
}

/* The two facts that become a line under the name on a phone. Hidden where the columns exist. */
.board-table__summary {
    display: block;
    margin-top: var(--space-3xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
}

.board-table__head-long {
    display: none;
}

.board-table__empty,
.board-table__note {
    margin: var(--space-xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

/* --- Where the captain places the team ---------------------------------------------------------
 * The invitation panel's neighbour, and built out of the same parts. Nothing new was designed.
 */
.placeform .field {
    margin-bottom: var(--space-sm);
}

.placeform .gate__label {
    color: var(--colour-text);
    font-weight: var(--font-weight-bold);
}

/* Inherited now, like every other select — this restated the field edge by hand while
 * `select.field__input` outranked the rule that gives it. See the note on that list. */
/* --- Wider than a phone -------------------------------------------------------------------------
 * The two narrow columns come back and the summary line under the name goes with them.
 */
@media (min-width: 48rem) {
    .board-table__wide {
        display: table-cell;
    }

    .board-table__summary {
        display: none;
    }

    .board-table__head-long {
        display: inline;
    }

    .board-table__head-short {
        display: none;
    }

    .filters {
        flex-direction: row;
        align-items: center;
        flex-wrap: wrap;
        gap: var(--space-sm);
        padding: var(--space-xs);
    }

    .filters__row {
        flex: 1 1 18rem;
    }

    .filters__row--secondary {
        flex: 0 1 14rem;
    }

    .filters__note {
        flex: 1 1 100%;
    }
}

/* --- Wider than a laptop ------------------------------------------------------------------------- */
@media (min-width: 64rem) {
    .filters {
        flex: 0 0 auto;
        flex-direction: column;
        align-items: stretch;
        width: 32rem;
    }

    .filters__row {
        flex: 0 0 auto;
    }

    .filters__row--secondary {
        flex: 0 0 auto;
        grid-auto-columns: 1fr;
    }

    .board-table {
        font-size: var(--font-size-base);
    }
}

/* === ADMINISTRATION =========================================================================
 *
 * The operator's product. Same tokens, same type scale, same card and the same focus states as
 * the participant screens — and a shell of its own, because the approved admin references draw a
 * different header, navigation and footer, and because an operator administering a campaign is
 * not participating in one.
 *
 * LAPTOP AND DESKTOP. Admin is not a phone product for this release. The layout still reflows and
 * never scrolls sideways, but nothing here spends effort on a mobile navigation pattern.
 *
 * QUIETER THAN THE PARTICIPANT SCREENS, ON PURPOSE. No hero band, no illustration, no wave
 * field: this is a workbench, and the references are right that the data should be the loudest
 * thing on it.
 */
/* Administration stands on the same ground as everything else; its own bar is the ink. */
.adminshell {
    background: var(--colour-surface-warm);
}

.adminpage {
    display: flex;
    flex-direction: column;
    gap: var(--space-lg);
    min-height: 100vh;
    /* 73rem less the side padding is the 1120px the references draw content in at 1440. Admin
     * was a little wider than that, which read as a denser page than the approved one. */
    /* The page no longer constrains: the bar and the footer are full-bleed, and the measure
     * is applied to their inner rows and to the main column. */
    padding: 0;
}

/* --- The header -------------------------------------------------------------------------------
 * The product's name centred above a rule, and the navigation under it. Two rows rather than one,
 * as the references draw it: the mark says which product this is, and the row below says where
 * you are in it.
 */
.adminbar {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    padding-block: var(--space-2xs);
}

.adminbar__mark {
    display: flex;
    align-items: baseline;
    justify-content: flex-start;
    gap: var(--space-xs);
    margin: 0;
}

.adminbar__product {
    color: var(--colour-text);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
}

/* The section word is the quieter half of the pair: it says which part of the product, and it
 * must never compete with the product's own name. */
.adminbar__section {
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    letter-spacing: var(--tracking-caps);
}

.adminbar__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
}

.adminnav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs);
}

/* A destination, not a button: the current one is filled with the page tint and announced with
 * aria-current, and the rest are plain. */
.adminnav__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
    padding: var(--space-3xs) var(--space-md);
    border-radius: var(--radius-lg);
    color: var(--colour-text);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-medium);
    text-decoration: none;
}

.adminnav__link--on {
    background: var(--colour-surface-badge);
    font-weight: var(--font-weight-bold);
}

.adminbar__who {
    display: flex;
    align-items: center;
    gap: var(--space-md);
}

/* A statement of what this operator is, not a menu. */
.adminbar__role {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.adminbar__out {
    margin: 0;
}

.adminbar__out .link-button {
    font-weight: var(--font-weight-bold);
}

.adminmain {
    flex: 1 1 auto;
    width: 100%;
    max-width: var(--shell-measure);
    margin: 0 auto;
    padding: var(--space-xl) var(--space-md) var(--space-2xl);
}

/* --- The footer ------------------------------------------------------------------------------- */
.adminfoot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    color: var(--colour-text-inverse);
}

.adminfoot__mark {
    margin: 0;
}

/* --- A screen's own heading ---------------------------------------------------------------------
 * Large, dark and unornamented. The references give admin a bigger heading than the body copy
 * would suggest, and it is the only decorative weight on the page.
 */
.adminhead__title {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-3xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
    letter-spacing: -0.01em;
}

/* A breadcrumb, used once: the editor is the only admin screen below the top level. */
.adminhead__trail {
    margin: 0 0 var(--space-2xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* --- The card the whole of admin is built from --------------------------------------------------
 * White, softly bordered, barely raised. Everything on these screens is one of these.
 */
.adcard {
    padding: var(--space-md);
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-xl);
    background: var(--colour-surface-raised);
}

.adcard__title {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
}

.adcard__lede {
    margin: var(--space-3xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

.adstack {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}

/* --- Overblik ---------------------------------------------------------------------------------
 * The campaign's state, four figures, what needs doing, and the doors to everything else.
 */

/* An outlined button, which the admin references use for everything that is not the one primary
 * action on a screen. Same geometry and same focus ring as .button; it only stops shouting. */
.button--quiet {
    width: auto;
    min-width: 0;
    border-color: var(--colour-border-soft);
    background: var(--colour-surface-raised);
    color: var(--colour-text);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
}

.button--quiet:hover {
    border-color: var(--colour-accent-on-surface);
    background: var(--colour-surface-badge);
}

.adstack__section {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.adminhead__title--small {
    font-size: var(--font-size-xl);
}

/* --- The campaign's state ----------------------------------------------------------------------
 * A tinted band rather than a white card: it is the context the figures below are read in, not
 * another figure among them.
 */
.campstate {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    padding: var(--space-md) var(--space-lg);
    border-radius: var(--radius-xl);
    background: var(--colour-surface-hero, var(--colour-surface-app));
}

.campstate__title {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
}

.campstate__dates {
    margin: var(--space-3xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-base);
}

/* --- The four figures --------------------------------------------------------------------------- */
.statrow {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr));
    gap: var(--space-sm);
    margin: 0;
    padding: 0;
    list-style: none;
}

.statcard {
    padding: var(--space-md);
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-xl);
    background: var(--colour-surface-raised);
}

.statcard__label {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.statcard__value {
    margin: var(--space-2xs) 0;
    color: var(--colour-text);
    font-size: var(--font-size-3xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
}

.statcard__note {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.attention__rows {
    display: flex;
    flex-direction: column;
    margin-top: var(--space-sm);
}

/* A rule between rows rather than around each: the panel is one list, and a box per row would
 * make three problems out of two facts. */
.attention__row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-xs) var(--space-sm);
    padding: var(--space-sm) 0;
    border-bottom: var(--border-width) solid var(--colour-border-soft);
}

.attention__row:last-child {
    padding-bottom: 0;
    border-bottom: 0;
}

.attention__figure {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
}

.attention__what {
    flex: 1 1 12rem;
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-base);
}

.attention__what--strong {
    color: var(--colour-text);
    font-weight: var(--font-weight-bold);
}

.attention__stack {
    flex: 1 1 12rem;
}

.attention__action {
    margin-left: auto;
    color: var(--colour-accent-on-surface);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    white-space: nowrap;
}

.nextmail__name {
    margin: var(--space-sm) 0 0;
    color: var(--colour-text);
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
}

.nextmail__action {
    margin: var(--space-md) 0 0;
}

/* --- E-mail Center --------------------------------------------------------------------------
 * Six cards in two groups. Each says what the message is for, whether it is ready, which
 * languages exist and when the copy was last touched — and offers one action.
 */
.mailcards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(19rem, 100%), 1fr));
    gap: var(--space-sm);
    margin: 0;
    padding: 0;
    list-style: none;
}

.mailcard {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding: var(--space-md);
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-xl);
    background: var(--colour-surface-raised);
}

.mailcard__title {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
}

.mailcard__purpose {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

.mailcard__chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs);
    margin: var(--space-2xs) 0 0;
}

/* A small stated fact. The status chip is tinted and the language chips are not, so the eye
 * reaches the state first; both are words either way. */
.chip {
    display: inline-flex;
    align-items: center;
    padding: var(--space-3xs) var(--space-xs);
    white-space: nowrap;
    border-radius: var(--radius-pill);
    background: var(--colour-surface-field);
    color: var(--colour-text);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
}

/* THE TEXT COLOUR LIVES ON THE BASE RULE, NOT HERE, and AccentColourTextTest is right to insist.
 * Forest Green is measured below 4.5:1 against Snow White and contrast is symmetric, so a rule
 * that names it and sets a text colour in the same breath is the shape that produces unreadable
 * text — even when, as here, the background is a 14% tint of it and the text is True Blue. The
 * modifier tints; the base carries the words. */
.chip--on {
    background: var(--board-positive-ground);
}

/* A language somebody has actually written, as against one still on its shipped default. */
.chip--written {
    background: var(--colour-surface-badge);
}

.mailcard__when {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* Pushed to the bottom so a row of cards has its buttons on one line however long the copy
 * above them runs. */
.mailcard__action {
    margin: auto 0 0;
    padding-top: var(--space-2xs);
}

.mailnote {
    margin: 0;
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-lg);
    background: var(--colour-surface-app);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* --- The e-mail editor -------------------------------------------------------------------------
 * Content on the left, the mail itself on the right. Four fields, no HTML, and a preview that is
 * the real message rather than a second rendering of the same words.
 */
.editor {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-md);
    align-items: start;
}

.editor__form {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

/* TIGHTER THAN THE PRODUCT'S DEFAULT FIELD, as the reference draws it. Four fields with the
 * product's participant-facing spacing pushed the save button below the fold on a laptop, which
 * turns "edit the wording and look at the result" into a scrolling exercise. */
.editform .field {
    margin-bottom: var(--space-xs);
}

.editform .field__label {
    margin-bottom: var(--space-3xs);
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

/* The field's own `#6675A3` edge, not a paler one: `--colour-border-soft` bounded these at 1.26:1,
 * where a control's boundary needs 3:1 (WCAG 2.2 AA 1.4.11) — the defect F-045 removed from three
 * participant controls. */
.editform .field__input {
    font-size: var(--font-size-base);
}

/* The body is the one field somebody writes paragraphs into, so it gets the room for them and a
 * monospace-free face: this is prose, not code, and it is never HTML. */
.editform__body {
    min-height: 11rem;
    line-height: var(--line-height-base);
    resize: vertical;
}

.editform__placeholders {
    margin: 0 0 var(--space-sm);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

.editform__placeholders code {
    padding: 0 var(--space-3xs);
    border-radius: var(--radius-sm);
    background: var(--colour-surface-field);
    color: var(--colour-text);
}

/* SAVE AND TEST SIT TOGETHER ON ONE ROW, as the reference draws them: they are the two things an
 * operator does after writing, and stacking them read as a hierarchy that is not there. They stay
 * two separate forms — a test is not a second submit button on the one that saves — so the row is
 * a flex container holding both. */
.editform__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-xs);
}

.editform__actions,
.editform__test {
    margin: 0;
}

.editform__default {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* The dispatch strip: what the state is, and the way to the compose flow that owns it. */
.dispatch {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    margin-bottom: var(--space-sm);
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-lg);
    background: var(--colour-surface-app);
}

.dispatch__label {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

.dispatch__detail {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* --- The preview ---------------------------------------------------------------------------------
 * A frame, because mail styling is inline and absolute and must not meet the product's own rules.
 */
.editor__preview {
    background: var(--colour-surface-raised);
}

.editor__preview-label {
    margin: 0 0 var(--space-xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

/* The mail sits on a tinted ground rather than flush against the card, as the reference draws it:
 * it is a message being looked at, not part of this page. */
.editor__stage {
    position: relative;
    padding: var(--space-sm);
    border-radius: var(--radius-lg);
    background: var(--colour-surface-app);
}

/* THE FRAME HOLDS ITS HEIGHT, AND IS TRANSPARENT UNTIL THE MAIL PAINTS (F-022, advisor Q4). It
 * was an empty white box until the document loaded; now the stage's "Loading preview" shows
 * through, centred, and the mail's own ground covers it when it arrives. */
.editor__frame {
    position: relative;
    z-index: 1;
    display: block;
    width: 100%;
    height: 30rem;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
}

.editor__loading {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.editor__plain {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-xs);
    margin: var(--space-xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

@media (min-width: 64rem) {
    /* The reference gives the writing room roughly three fifths and the preview two. An even
     * split made the form the narrower of the two in practice, because its fields carry padding
     * and the preview does not — so the thing being written was the cramped half. */
    .editor {
        grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
    }
}

/* --- Brugere & support ---------------------------------------------------------------------
 * Search and a compact table, with the person being helped beside them.
 */
.supportwork {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-md);
    align-items: start;
}

.supportwork__main {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    min-width: 0;
}

.supportsearch__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
}

.supportsearch__input {
    flex: 1 1 18rem;
    border-color: var(--colour-border-soft);
    border-radius: var(--radius-lg);
    font-size: var(--font-size-base);
}

.supportsearch__hint {
    margin: var(--space-2xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.supporttable {
    padding: var(--space-sm);
}

/* THE COLUMNS ARE SIZED, BECAUSE THE FIXTURE LIED.
 *
 * The design's fixture uses k.larsen@novo.com. Novo's actual addresses are @novonordisk.com, and
 * with the columns left to the browser every row broke: the name wrapped onto two lines, the team
 * wrapped, and the address split mid-word into "…novonordisk.co / m". A support operator scanning
 * for one person reads a column of ragged two-line rows far slower than the one-line rows the
 * reference draws.
 *
 * So the address gets the room it needs and the four short columns are held to their content.
 * Fixed layout, so one long team name cannot take the table apart. */
.supporttable .board-table {
    table-layout: fixed;
}

.supporttable .board-table th:nth-child(1),
.supporttable .board-table td:nth-child(1) {
    width: 40%;
}

.supporttable .board-table th:nth-child(2),
.supporttable .board-table td:nth-child(2) {
    width: 34%;
}

.supporttable .board-table th:nth-child(3),
.supporttable .board-table td:nth-child(3) {
    width: 26%;
}

/* THE ADDRESS KEEPS ONE LINE, with an ellipsis and the full value in the panel beside the table.
 * A NAME DOES NOT (F-043, advisor 2026-09-23): the name cell wraps at spaces and hyphens and the
 * row grows — see .supporttable__who. The last column is a team name, short enough to be left
 * alone. */
.supporttable .board-table td:not(:first-child):not(:last-child) {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The row's control. A button, because selecting a row posts the search term with it; it is drawn
 * as the name itself and fills the cell, so the whole name is the target rather than a few words
 * of it. */
.supporttable__pick {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    width: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    color: var(--colour-text);
    font: inherit;
    text-align: inherit;
    cursor: pointer;
}

.supporttable__pick:hover .supporttable__who {
    text-decoration: underline;
}

.board-table__row--you .supporttable__pick {
    font-weight: var(--font-weight-bold);
}

.supporttable__empty {
    margin: var(--space-sm) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.supporttable__empty {
    margin-top: 0;
    padding: var(--space-md);
}

/* --- The person being helped ------------------------------------------------------------------ */
.selectedcard {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.selectedcard__head {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}

/* The same initials mark the participant shell uses, drawn from the stated name rather than
 * stored, so there is no second copy of anybody's identity to keep correct. */
.selectedcard__initials {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    background: var(--colour-primary);
    color: var(--colour-surface);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

.selectedcard__name {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
}

.selectedcard__status {
    margin: var(--space-3xs) 0 0;
}

/* A labelled list of facts, ruled between rows so the eye can run down the values. */
.factlist {
    margin: 0;
}

.factlist__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs) var(--space-sm);
    padding: var(--space-xs) 0;
    border-bottom: var(--border-width) solid var(--colour-border-soft);
}

.factlist__row:last-child {
    border-bottom: 0;
}

.factlist__label {
    flex: 0 0 5rem;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.factlist__value {
    flex: 1 1 10rem;
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    overflow-wrap: anywhere;
}

.factlist__via {
    color: var(--colour-text-muted);
}

.selectedcard__actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
}

.selectedcard__actions .button {
    width: 100%;
}

/* Said once, quietly, where an operator is about to act: this is a logged workspace. */
.selectedcard__audited {
    margin: 0;
    padding: var(--space-sm);
    border-radius: var(--radius-lg);
    background: var(--colour-surface-app);
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    line-height: var(--line-height-base);
}

@media (min-width: 64rem) {
    /* The panel is held to the width the reference draws it at rather than growing with the
     * page: it holds five short facts and three buttons, and every pixel it takes beyond that
     * comes out of the table, which is the half with five columns to fit. */
    .supportwork {
        grid-template-columns: minmax(0, 1fr) minmax(20rem, 23rem);
    }
}

.supporttable__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-sm);
    margin-top: var(--space-sm);
}

.supporttable__pages {
    display: flex;
    gap: var(--space-2xs);
}

/* === THE UNAUTHENTICATED SHELL ==============================================================
 *
 * The approved Direction A photo split. An approved Novo photograph fills the left of the
 * laptop; a calm white column on the right holds the one thing there is to do. Seven screens
 * wear it, and the photograph changes with the phase of the journey so they read as one.
 *
 * NOTHING IS DRAWN OVER A PERSON. The mark sits on a flat True Blue plate in the top corner and
 * that is the whole of it — no translucent wash over a face, no gradient scrim, no text laid
 * across the frame, and no bar along the foot. A strapline used to sit there and was removed:
 * it competed with the mark, repeated the footer, and on a phone it crossed a colleague.
 *
 * THE CROP IS CSS, so it answers to the viewport. A 16:9 photograph in a tall panel has to lose
 * something, and each one names the part of itself worth keeping rather than defaulting to the
 * centre and cutting a colleague in half.
 */
/* === THE GUEST AND SIGN-IN SHELL ===============================================================
 * ONE PRODUCT, NOT TWO. These seven screens used to be a full-height photograph beside a white
 * column, which was its own design: a visitor met one product before signing in and a different
 * one afterwards. They now stand on the same warm ground as the rest of STEP COUNT, under the same
 * light bar, with the task on one white panel — the participant screens' panel, at the width a
 * single task deserves rather than the width of a fortnight of data.
 *
 * THE PHOTOGRAPH IS NOT GONE, it has stopped being the layout. It appears once, on the landing
 * page, as a contained band inside the column where it illustrates the campaign instead of holding
 * up half the screen. No auth screen carries one: a person signing in is doing a ten-second job.
 */
.gateshell {
    background: var(--colour-surface-warm);
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.gatebar {
    background: var(--colour-surface-warm);
    border-bottom: var(--border-width) solid var(--colour-border-on-warm);
}

/* NO RULE UNDER THE SHARED BAR. Main.dc.html draws it as warm ground running into warm ground,
 * and the landing page already dropped the border for itself.
 *
 * ON A MODIFIER, NOT ON `.gatebar`. ACC-001 first made these figures the bar's own, which also
 * restyled the onboarding family — screens the brief excludes — from a 64px bordered bar to an
 * 88px borderless one on a wider gutter, with the language control changing shape. Review
 * caught it. `gatebar--shared` is carried only by partials/public-header.blade.php, so the six
 * screens ACC-001 names get the board's bar and the three it excludes keep theirs. */
.gatebar--shared {
    border-bottom: 0;
}

.gatebar__inner,
.gatemain__inner {
    width: 100%;
    max-width: var(--shell-measure);
    margin: 0 auto;
    padding-inline: var(--space-md);
}

.gatebar__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2xs) var(--space-md);
    padding-block: var(--space-2xs);
    min-height: var(--touch-target-min);
}

/* THROUGH THE SHARED BAR, NOT THROUGH THE SHELL. This was `.gateshell .gatemark`, which is a
 * class on the gate family's <body>; /materials renders the same bar from layouts/public and has
 * no such class, so the mark fell back to the centred, muted, margin-bearing base rule.
 *
 * AND ON THE MODIFIER, because 17px is the shared board's figure. Unscoped it also reached the
 * onboarding mark, whose own board draws 16 — a one-pixel difference no markup test can see,
 * which is exactly the class of leak the modifier exists to stop. */
.gatebar--shared .gatemark {
    margin: 0;
    font-weight: var(--font-weight-bold);
    color: var(--colour-text);

    /* 17px, THE BOARD'S, AND DELIBERATELY NOT --font-size-base. Main.dc.html, GuestAuth.dc.html
     * and GuestMaterials.dc.html all draw the wordmark at 17/700/0.18em; the token is 16, so the
     * mark rendered about 6% short on all six routes. */
    font-size: 17px;

    /* 0.18em, THE BOARD'S FIGURE, STATED HERE RATHER THAN TAKEN FROM --tracking-caps.
     *
     * The token is 0.05em. A rule further down this file widens `.gatemark` to the board's
     * 0.18em, and it is written as `.gateshell .gatemark, .gatemark` — which on a gate screen
     * outranks this block and on /materials does not, because that page's <body> carries no
     * `gateshell` class. The wordmark therefore measured 142px on /sign-in and 121px on
     * /materials: the same six routes, the same markup, two different marks. Caught by reading
     * the computed style in a browser; no markup assertion could have seen it. */
    letter-spacing: 0.18em;
}

/* A LINK ON EVERY SCREEN, INCLUDING ITS OWN (ACC-001). It was a bare <p> in the gate family, so
 * /sign-in had no way back to the front page but the browser's own.
 *
 * AND IT IS A TARGET, NOT JUST A WORD. It shipped as a bare inline <a> around a 16px span —
 * about 19px tall, under the 44/48 floor Foundations.dc.html sets, on the one control that is
 * the only route home from four of the six screens on a phone. The links and the pill beside it
 * already carried the floor; this did not. */
.gatebar__brand {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
    text-decoration: none;
    color: inherit;
}

.gatebar__brand:hover .gatemark {
    text-decoration: underline;
}

.gatemain {
    flex: 1 1 auto;
    padding-block: var(--space-2xl);
}

/* ONE COLUMN, CENTRED — and on the landing page two, because that screen has something to say
 * beside the form. The card keeps its own width in both, so the task is the same object wherever
 * somebody meets it. */
.gatemain__inner {
    display: flex;
    justify-content: center;
}

/* ONE COLUMN AS WIDE AS THE SCREEN, NOT AS WIDE AS ITS WIDEST LINE (F-052). A bare `1fr` floors
 * the column at its content's min-content, so at 320 the page scrolled 6px sideways; `minmax(0,
 * 1fr)` holds it to the viewport, and the phone's campaign panel is sized to fit it below. */
.gatemain--split .gatemain__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-lg);
    align-items: start;
}

/* THE PANEL IS 24rem UNLESS ITS FIGURE NEEDS MORE (F-052). The step total is 68px and does not
 * wrap, and a fixed 24rem leaves 320px inside the panel's padding: a seven-digit total overflowed
 * the viewport between 1024 and 1279. `minmax(min-content, 24rem)` is 24rem whenever the content
 * fits it, which is every campaign so far, and grows only when it does not. */
@media (min-width: 64rem) {
    .gatemain--split .gatemain__inner {
        grid-template-columns: minmax(0, 1fr) minmax(min-content, 24rem);
        gap: var(--space-xl);
    }
}

/* The photograph, where it illustrates rather than dominates: one band, the content width, the
 * product's own corner. Decorative, so it is announced to nobody. */

/* --- The one card the whole family is built around ---------------------------------------------
 * ONE FIXED WIDTH, on every screen, in both languages. The thing somebody is doing is the same
 * object wherever they meet it, and only what surrounds it changes.
 *
 * NO BORDER AND NO SHADOW. The approved direction keeps the right-hand column completely calm:
 * the photograph is the only weight on the screen, and a raised panel floating on white beside it
 * would be a second one.
 */
.gatecard {
    width: 100%;
    max-width: 30rem;
    padding: var(--space-xl);
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-2xl);
    background: var(--colour-surface);
}

@media (max-width: 47.99rem) {
    .gatecard {
        padding: var(--space-lg);
    }
}

.gatecard h1 {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-3xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
    letter-spacing: -0.01em;
}

.gatecard__lede {
    margin: var(--space-xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-base);
    line-height: var(--line-height-base);
}

.gatecard .field {
    margin-top: var(--space-lg);
}

.gatecard .gate__label {
    display: block;
    margin-bottom: var(--space-2xs);
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

/* A LABEL THAT OPENS A FORM CARRIES ITS OWN SPACE. Sign in and create-a-team put a bare label
 * straight after the lede rather than wrapping it in .field, so it inherited nothing and sat
 * tight against the sentence above it — the label read as a third line of the lede. The child
 * combinator is what keeps this off the labels inside .field, which are already spaced. */
.gatecard .gate__form > .gate__label {
    margin-top: var(--space-lg);
}

.gatecard .gate__hint {
    display: block;
    margin-bottom: var(--space-2xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

.gatecard .button {
    width: 100%;
    margin-top: var(--space-lg);
}

.gatecard .button--quiet {
    width: 100%;
    margin-top: var(--space-xs);
}

.gatecard__note {
    margin: var(--space-md) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

.gatecard__steps {
    margin: var(--space-md) 0 0;
    padding: 0;
    list-style: none;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

.gatecard__steps li {
    position: relative;
    padding-left: var(--space-md);
}

.gatecard__steps li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.65em;
    width: 6px;
    height: 6px;
    border-radius: 50%;
}

/* --- Wider than a phone -------------------------------------------------------------------------
 * THE SPLIT ARRIVES HERE, and below it the photograph is a band above the work rather than a
 * column beside it. That is the approved mobile composition, not a squeezed desktop: the band is
 * a third of the screen, the line across its foot goes, and the card takes the room.
 */
@media (min-width: 64rem) {
    .gatesplit {
        grid-template-columns: 46% 1fr;
        grid-template-rows: 1fr;
    }

    .gatesplit__middle {
        padding: var(--space-lg) var(--space-xl);
    }
}

@media (max-width: 63.99rem) {
    /* THE BAND IS A HEADER, NOT A HALF-SCREEN. A third of the viewport looked right in
     * isolation and was wrong in use: on a 390x844 phone it pushed the heading past 300px and
     * left the last line of the screen's own copy under the fold, which is the one thing a
     * first screenful must not do. Roughly 29vh keeps the photograph unmistakably present and
     * gives the work above the fold. The clamp holds it sane on a short landscape phone and on
     * a tablet, where 29vh would be a postage stamp or a poster. */
    .gatesplit__image {
        height: 29vh;
        min-height: 9rem;
        max-height: 15rem;
    }

    .gatesplit__plate {
        left: var(--space-md);
        top: var(--space-sm);
    }

    /* The language switch sits against the photograph rather than floating in a band of its
     * own: the vertical room it was taking is room the heading needed. */
    .gatesplit__top {
        padding: var(--space-xs) var(--space-md) 0;
    }

    .gatesplit__foot {
        padding: var(--space-xs) var(--space-md) var(--space-sm);
    }

    .gatesplit__middle {
        align-items: flex-start;
        padding: var(--space-2xs) var(--space-md) var(--space-md);
    }

    /* 2.25rem is a laptop heading. On a 390px screen it wraps sooner, costs a line, and the
     * line it costs is the one the button needed. */
    .gatecard h1 {
        font-size: var(--font-size-2xl);
    }

    .gatecard__lede {
        margin-top: var(--space-2xs);
    }

    /* Tighter between the parts of the card, and no tighter than that: every control keeps its
     * own height, so the targets stay the size a thumb needs and only the air between them
     * goes. */
    .gatecard .field,
    .gatecard .gate__form > .gate__label {
        margin-top: var(--space-sm);
    }

    .gatecard .gate__hint {
        margin-bottom: var(--space-3xs);
    }

    .gatecard .button {
        margin-top: var(--space-sm);
    }
}

/* --- The two panels underneath -----------------------------------------------------------------
 * Side by side on a laptop, stacked on a phone. Not cards: the reference gives these the page's
 * own surface and lets the headings carry the structure, which keeps the three-step band above
 * them as the only place the eye stops.
 */

/* An anchor styled as the product's button: inline-flex so it sizes to its words rather than
 * stretching, which .button does for a form's submit. */

/* --- The navigation breathes on a laptop (QA-014) ----------------------------------------------
 *
 * .bar's gap is --space-xs, and the comment there explains why: eight destinations and the way
 * out had to fit one line, and at --space-sm "Sign out" wrapped alone onto a second row.
 *
 * THAT CONSTRAINT HAS EASED. A captain now has five destinations and an ordinary participant four
 * — Mit hold left the member's bar with QA-013 — so on a laptop there is room the approved
 * references use: their navigation is noticeably more open than ours was, and a cramped row is
 * the first thing that makes a page look unfinished next to them.
 *
 * ONLY WHERE THERE IS ROOM. Below this width the original value stands, so the wrap that comment
 * describes cannot come back on a narrow window or a phone.
 */
@media (min-width: 64rem) {
    .bar {
        gap: var(--space-md);
    }
}

/* The way to retire a shared link. Quiet: most captains will never need it. */
.invite__rotate {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2xs);
    margin-top: var(--space-xs);
}

/* ==========================================================================================
 * THE SHELL — 2026
 *
 * WHAT CHANGED AND WHY. The product read as a document with a row of links above it: a pale
 * blue wash everywhere, a hairline under the navigation, and every surface the same weight.
 * The frame is now True Blue and full-bleed — the bar at the top, the footer at the bottom —
 * and the screen itself is white inside it. That is the brand's own register: [NOVO] asks for
 * True Blue and Snow White above all, permits full-colour fields, and supplies a white wordmark
 * precisely for dark grounds. White on True Blue measures 15.83:1.
 *
 * ONE FRAME FOR EVERY ROLE. The participant bar and the admin bar are the same object with
 * different destinations, so Mine skridt and Overblik read as one product rather than as an app
 * and its back office.
 *
 * These rules sit at the end of the file deliberately: they are the shell's single definition,
 * and the older component rules they replace have had the conflicting declarations removed
 * rather than left to fight the cascade.
 * ========================================================================================== */

/* TWO BARS, ONE OBJECT. The participant bar sits on the warm ground with a hairline under it,
 * because a participant screen is a light screen and a solid ink band across the top of it fought
 * the panels below. Administration keeps the ink field: an operator has to know at a glance that
 * they are in the back office, and that is the one place the product says so without words. */
.appbar {
    background: var(--colour-surface-warm);
    color: var(--colour-text);
    border-bottom: var(--border-width) solid var(--colour-border-on-warm);
}

.adminshell .adminbar {
    background: var(--colour-surface-ink);
    color: var(--colour-text-inverse);
}

.appbar__inner,
.adminshell .adminbar__mark,
.adminshell .adminbar__row {
    width: 100%;
    max-width: var(--shell-measure);
    margin: 0 auto;
    padding-inline: var(--space-md);
}

.appbar__inner {
    display: flex;
    align-items: center;
    padding-block: var(--space-2xs);
}

/* The bar's own contents inherit the inverse colour rather than each restating it: one rule
 * decides what "on the ink" means, and a new control added to the bar tomorrow is already
 * right. */
.adminshell .adminbar__product,
.adminshell .adminbar__section,
.adminshell .adminnav__link,
.adminshell .adminbar__role,
.adminshell .adminbar__out .link-button {
    color: var(--colour-text-inverse);
}

.appbar .gatemark {
    margin: 0;
    text-align: left;
    font-size: var(--font-size-base);
}

.appbar .topbar {
    flex: 1 1 auto;
    margin: 0;
    padding: 0;
    border: 0;
    gap: var(--space-sm) var(--space-lg);
}

/* WHERE YOU ARE, AS A SHAPE RATHER THAN AS AN UNDERLINE. A 2px rule under a word is a weak
 * signal on either field, so the current destination is a filled pill: True Blue on the light
 * participant bar, Snow White on the ink admin bar. Weight and shape carry it, never colour
 * alone (WCAG 2.2 AA 1.4.1), and the attribute that draws it is the one assistive technology
 * reads. */
.appbar .bar__link,
.adminshell .adminnav__link {
    padding: var(--space-3xs) var(--space-sm);
    border-radius: var(--radius-pill);
    /* tokens.css calls 44px "the accessibility floor", and the phone menu's destinations are
     * exactly where that matters. The pill shape does not need a shorter control. */
    min-height: var(--touch-target-min);
}

.appbar .bar__link {
    color: var(--colour-text-muted);
    font-weight: var(--font-weight-medium);
}

.appbar .bar__link[aria-current='page'] {
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
    box-shadow: none;
    font-weight: var(--font-weight-bold);
}

.adminshell .adminnav__link--on {
    background: var(--colour-surface);
    color: var(--colour-primary);
    box-shadow: none;
    font-weight: var(--font-weight-bold);
}

.appbar .bar__link:hover,
.appbar .bar__link:focus-visible {
    background: var(--colour-surface-sunken);
    color: var(--colour-primary);
    text-decoration: none;
}

.adminshell .adminnav__link:hover,
.adminshell .adminnav__link:focus-visible {
    background: var(--colour-surface-ink-raised);
    text-decoration: none;
}

.appbar .bar__link[aria-current='page']:hover {
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
}

.adminshell .adminnav__link--on:hover {
    background: var(--colour-surface);
}

/* The focus ring is drawn in white here: the ink field swallows a True Blue one.
 *
 * .inkpanel BELONGS ON THIS LIST AND WAS MISSING FROM IT. It is the same True Blue ground, and
 * the one control standing on it — the diploma's own action, and the address link on the Support
 * page — had a True Blue ring on True Blue: 1:1, which is no ring at all. The button's only other
 * focus change is its background going from white to #ccd1e0, a 1.53:1 step where a focus
 * indicator needs 3:1 (WCAG 2.2 AA, 1.4.11). Found by review, not by the browser walk, which
 * measures whether an outline exists and not whether it can be seen. */
.adminshell .adminbar :focus-visible,
.sitefoot :focus-visible,
.adminshell .adminfoot :focus-visible,
.inkpanel :focus-visible {
    outline-color: var(--colour-text-inverse);
}

.appbar .whoami {
    margin: 0;
}

.appbar .whoami__initials {
    background: var(--colour-primary);
    border: 0;
    color: var(--colour-text-inverse);
}

/* The role beside the operator's name, on the ink admin bar. */
.adminshell .adminbar__role {
    color: var(--colour-accent-on-primary);
}

/* The same line on the light participant bar reads as ordinary muted text. */
.appbar .whoami__role,
.appbar .navmenu__person {
    color: var(--colour-text-muted);
}

/* --- The page inside the frame -------------------------------------------------------------
 * White, wide and quiet. The pale blue wash that used to cover every screen has gone: a tint is
 * now something a section EARNS — the step entry panel, a public band — rather than the default
 * state of the product.
 */
/* THE GROUND IS WARM, AND THE PANELS ARE THE WHITE. A tint of Sand Grey under everything is
 * what stops the product reading as an internal tool: a white card now has something to sit on,
 * and white is spent on the thing being read rather than on the page. Approved on Mine skridt
 * and rolled out from there. */
body {
    background: var(--colour-surface-warm);
}

.page {
    max-width: var(--shell-measure);
    padding: var(--space-lg) var(--space-md) var(--space-2xl);
}

/* The gate screens keep the narrow measure: one field wants one column, not a 1168px field. */
.gate-page .page {
    max-width: 36rem;
}

/* --- The footer ------------------------------------------------------------------------------ */
.sitefoot,
.adminshell .adminfoot {
    background: var(--colour-surface-ink);
    color: var(--colour-text-inverse);
    border: 0;
    margin-top: var(--space-2xl);
}

.sitefoot__inner,
.adminshell .adminfoot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm) var(--space-lg);
    width: 100%;
    max-width: var(--shell-measure);
    margin: 0 auto;
    padding: var(--space-lg) var(--space-md);
    font-size: var(--font-size-sm);
}

.sitefoot .page__footer-brand,
.adminshell .adminfoot__mark {
    margin: 0;
    color: var(--colour-text-inverse);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
}

/* The admin boards' footer mark: STEP COUNT at 15px, tracked 0.18em like the bar's. Its own
 * rule, because the list above also sets the participant footer, which keeps its own. */
.adminshell .adminfoot__mark {
    font-size: 15px;
    letter-spacing: 0.18em;
}

/* The section after the product name: the boards' second voice, #C9D6F0 at 600 and untracked. */
.adminshell .adminfoot__section {
    color: var(--colour-text-on-primary-muted);
    font-weight: var(--font-weight-semibold);
    letter-spacing: normal;
}

.sitefoot .page__operator {
    margin: 0;
    color: var(--colour-accent-on-primary);
}

.sitefoot .language,
.adminshell .adminfoot .language {
    color: var(--colour-accent-on-primary);
}

.sitefoot .language__current,
.adminshell .adminfoot .language__current {
    color: var(--colour-text-inverse);
}

.sitefoot .language__choice,
.sitefoot .language .link-button,
.adminshell .adminfoot .language__choice,
.adminshell .adminfoot .language .link-button {
    color: var(--colour-text-inverse);
}

/* ==========================================================================================
 * SURFACES AND COMPONENTS — 2026
 *
 * THE RHYTHM. White is the ground. A tint is something a surface earns — the box a number is
 * typed into, a band that separates one idea from the next — rather than the state everything
 * starts in. [NOVO] asks for whitespace as the defining characteristic and for tints alongside
 * True Blue and Snow White, not instead of them; the old pale-blue wash under every card had
 * turned the tint into the default and left nothing to emphasise with.
 *
 * THE HIERARCHY. One title per screen, set large and tight; an eyebrow above it for context;
 * figures larger than headings, because on this product the number IS the content. Panels are
 * white with a hairline and a generous corner, and never nest a tinted box inside a tinted box.
 * ========================================================================================== */

/* --- Panels ---------------------------------------------------------------------------------
 * One card family across participant, captain and admin: white, hairline, a corner you can see,
 * and room inside. No shadow — a hairline on white is quieter and holds at any zoom.
 */
.panel,
.adcard,
.roster-panel {
    padding: var(--space-lg);
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-2xl);
    background: var(--colour-surface);
    box-shadow: none;
}

.pagestack {
    gap: var(--space-lg);
}

/* --- Section headings inside a panel -------------------------------------------------------- */
.panel__head {
    align-items: center;
    gap: var(--space-sm);
    margin-bottom: var(--space-md);
}

.panel__title,
.adcard__title {
    font-size: var(--font-size-xl);
    letter-spacing: var(--tracking-tight);
}

.panel__icon {
    width: 2rem;
    height: 2rem;
}

/* --- Buttons --------------------------------------------------------------------------------
 * One shape for every action in the product: a pill, because a 4px corner on a 48px control
 * reads as a rectangle with a mistake in it, and because the pill is unmistakably a control
 * beside the square fields it sits next to.
 */
.button {
    padding: var(--space-2xs) var(--space-lg);
    border-radius: var(--radius-pill);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.01em;
}

.button--secondary {
    background: transparent;
    border: var(--border-width-strong) solid var(--colour-primary);
    color: var(--colour-primary);
}

.button--secondary:hover,
.button--secondary:focus-visible {
    background: var(--colour-surface-field);
}

.button--quiet {
    border-radius: var(--radius-pill);
}

/* --- Fields ---------------------------------------------------------------------------------
 * A number on this product is typed far more often than it is read, so the box it is typed into
 * is large, white and squarely bounded — the tinted box inside a tinted card had made the field
 * the quietest thing on the screen.
 */
/* NO `select.field__input` IN THIS LIST, AND THAT IS THE WHOLE OF F-045's SELECT HALF.
 *
 * It used to be here, and being ELEMENT-qualified made it specificity 0,1,1. The rule further
 * down that modernised every field to `1px solid var(--colour-border-field)` is `.field__input,
 * .field__select` — 0,1,0 — so for a SELECT it lost regardless of source order, and every
 * select in the product kept a 2px `--colour-border` edge at 1.94:1 on white. The only ones
 * that cleared WCAG 2.2 AA 1.4.11 were the ones a screen had overridden by hand, which is why
 * `.profileform` and `.placeform` had needed scoped rules at all: each was working around this
 * line rather than inheriting a correct one.
 *
 * THE QUALIFIER HELD THE WHOLE RULE, NOT THE BORDER. Every declaration here dropped a point
 * for selects, so `.field__input, .field__select` further down now also supplies a select's
 * padding and font size — measured on `/team`, 8px/16px becomes 0/14px and `1rem` becomes
 * `16px`. That is the intended end: a select takes what the input beside it already takes, and
 * that block is px throughout, so selects were the outlier rather than this being a new
 * deviation. `min-height`, `background` and `border-radius` do not move anywhere, because every
 * select sits inside a screen rule that already outranked this one for them.
 *
 * An earlier draft of this comment said the height, padding, background and font size were
 * unchanged. They are not, and saying so was the same kind of arithmetic mistake as the one
 * recorded on the gate rule below. Found by design review.
 *
 * Driven at 1440 and 390 before and after — see the brief. Advisor's decision, 2026-09-24. */
.field__input,
.field__select {
    min-height: 3rem;
    padding: var(--space-2xs) var(--space-sm);
    border: var(--border-width-strong) solid var(--colour-border);
    border-radius: var(--radius-lg);
    background: var(--colour-surface);
    font-size: var(--font-size-base);
}

.field__input:focus-visible,
.field__select:focus-visible {
    border-color: var(--colour-primary);
}

/* THE LABEL IS A WORD, NOT A HEADING. Small caps in muted blue read as a section marker over a
 * field and made the two-word labels on the step screen ("Konverteret") longer than the box they
 * name. Sentence case, bold, in the text colour: it sits close above its input and scans as part
 * of it. Same treatment for every field in the product, so Aktivitet and Skridt look alike. */
.field__label {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    letter-spacing: normal;
    text-transform: none;
    color: var(--colour-text);
}

/* --- Status ---------------------------------------------------------------------------------
 * A confirmation or a refusal, marked by a rule in the status colour and carried by its words.
 */
.status {
    border-radius: var(--radius-lg);
    border-left: var(--border-width-accent) solid var(--colour-info);
    background: var(--colour-surface-field);
}

.status--warning {
    border-left-color: var(--colour-warning);
}

.status--error {
    border-left-color: var(--colour-danger);
}

/* --- Tables and rosters ---------------------------------------------------------------------
 * Rows separated by rules rather than boxed in a frame, headers as small caps, and the reader's
 * own row marked with an accent rule as well as a tint (WCAG 2.2 AA 1.4.1).
 */
.roster-table {
    border: 0;
}

/* THE TWO TABLES, AND NOTHING ELSE. `.results` and `.history` read like tables and are not: both
 * are <ol> lists of support rows, so a th/td rule aimed at them styles nothing and tells the next
 * reader a table exists where none does. */
.roster-table th,
.support__table th {
    padding: var(--space-2xs) var(--space-sm);
    border-bottom: var(--border-width-strong) solid var(--colour-border-soft);
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
}

/* ONLY WHERE THESE ARE STILL TABLES. Below 48rem the roster and the board are stacked blocks —
 * the phone layout sets `display:block` on the cells — and putting cell padding and a hairline
 * back on each block broke the roster into a grid of part-length rules and squeezed the board's
 * name column until colleagues' names wrapped mid-word. Design review caught both. */
@media (min-width: 48rem) {
    .roster-table td {
        padding: var(--space-sm);
        border-bottom: var(--border-width) solid var(--colour-border-soft);
    }
}

/* A SUPPORT TABLE IS A TABLE AT EVERY WIDTH, unlike the roster above, which stacks on a phone —
 * except where its scroller opts in to `support__scroller--cards` (admin.css, THE CARDTABLE).
 * It shared that rule, so below 48rem its cells kept the base rule's zero left padding while
 * the headers kept theirs, and every column read offset from its heading. Its own rule, at
 * every width. */
.support__table td {
    padding: var(--space-sm);
    border-bottom: var(--border-width) solid var(--colour-border-soft);
}

/* A NARROW TABLE MAY WRAP ON A PHONE, INSIDE AN ADDRESS IF IT MUST. Test access's two columns,
 * held on one line, needed a sideways scroll at 390 to reach the account state, which is the
 * only thing the column adds; SuperOps.dc.html breaks an address anywhere for the same reason.
 * Opt-in, not the default: a five-column table allowed to wrap was squeezed to one character a
 * column beside a note that kept its width, so the wide tables keep one line a cell and scroll. */
@media (max-width: 47.99rem) {
    .support__table--wraps th,
    .support__table--wraps td {
        white-space: normal;
        overflow-wrap: anywhere;
    }
}

/* --- The gate cards -------------------------------------------------------------------------- */
.gate {
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-2xl);
    padding: var(--space-xl) var(--space-lg);
    box-shadow: var(--shadow-md);
}

.gate-page {
    background: var(--colour-surface-warm);
}

/* --- The staging QA bar ----------------------------------------------------------------------
 * It sits above the product's own ink bar, so it must be the one thing on the page that is not
 * in the product's palette family — deliberate tooling, not debug furniture.
 */
/* A STEP LIGHTER THAN THE BAR BENEATH IT. Both banners were True Blue, and so is the product's
 * own bar now, so "you are in a QA context" and "you are inside somebody's account" read as part
 * of the chrome rather than as an overlay on it. The raised tint separates them; the accent rule
 * under each still says which is which. */
.qabar,
.impersonation {
    background: var(--colour-surface-ink-raised);
}

.qabar {
    padding: var(--space-3xs) var(--space-md);
    border-bottom: var(--border-width-accent) solid var(--colour-warning);
    font-size: var(--font-size-sm);
}

/* The skip link has to paint above the two sticky banners, which sit in the same strip at z-index
 * 99 and 100 — a focused control that is covered by other chrome is not visible focus
 * (WCAG 2.2 AA 2.4.11). */
.skip-link {
    z-index: 200;
}

/* --- The converter ---------------------------------------------------------------------------
 * Part of the same panel rather than a box inside it: a rule, a small heading, one row of
 * controls. The behaviour is untouched — preview, add to the day, and Save as the only
 * persistence boundary (ADR 017).
 */
.converter {
    margin-top: var(--space-lg);
    padding: var(--space-lg) 0 0;
    border: 0;
    border-top: var(--border-width) solid var(--colour-border-soft);
    border-radius: 0;
    background: transparent;
}

.converter__title {
    font-size: var(--font-size-lg);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
}

/* THE ANSWER IS WHAT THE BAND IS FOR. It was a caption and a small number wedged between the
 * fields and the button, which read as a technical readout rather than as the result of the
 * conversion. It is one large True Blue numeral with "Tilføj til dagen" immediately after it —
 * and no box: a bounded box here made the answer look like a field to type into (F-050). */
.converter__result {
    align-items: center;
}

.converter__result-label {
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.converter__result-value {
    font-size: var(--font-size-2xl);
    line-height: 1.1;
    letter-spacing: var(--tracking-tight);
    color: var(--colour-primary);
    font-variant-numeric: tabular-nums;
    font-weight: var(--font-weight-bold);
}

/* Muted and regular, never sized. Two classes would beat every width's one-class figure size
 * below, so a size here shrank the empty dash to 28 at every width while the number beside it
 * was 42 (F-050). The weight is the same specificity fact used on purpose: the figure's bold is
 * one class, and a bold dash at 42 is a bar (F-055). */
.converter__result--empty .converter__result-value {
    color: var(--colour-text-muted);
    font-weight: var(--font-weight-regular);
}

/* --- The language switcher on the ink footer ------------------------------------------------- */
.sitefoot .language__label,
.adminshell .adminfoot .language__label {
    color: var(--colour-accent-on-primary);
}

.sitefoot .language__choice,
.adminshell .adminfoot .language__choice {
    color: var(--colour-text-inverse);
}

/* --- Segmented controls -----------------------------------------------------------------------
 * Two views of the same board, and the scope inside one. A segmented control rather than a row
 * of buttons: the choices are exclusive, they belong to one question, and the chosen one is
 * filled with the product's blue so it is unmistakable at a glance (WCAG 2.2 AA 1.4.1 — the
 * label and aria-current carry it too).
 */
.boardtabs {
    display: inline-flex;
    gap: var(--space-3xs);
    padding: var(--space-3xs);
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-pill);
    background: var(--colour-surface-field);
}

.boardtabs__tab {
    min-height: 2.75rem;
    padding: var(--space-2xs) var(--space-lg);
    border: 0;
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--colour-text);
    font-weight: var(--font-weight-bold);
    text-decoration: none;
}

.boardtabs__tab--on {
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
}

.filters {
    gap: var(--space-2xs);
    padding: 0;
    border: 0;
    background: transparent;
}

.filters__choice {
    min-height: var(--touch-target-min);
    padding: var(--space-3xs) var(--space-md);
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-pill);
    background: var(--colour-surface);
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.filters__choice--on {
    background: var(--colour-primary);
    border-color: var(--colour-primary);
    color: var(--colour-text-inverse);
    font-weight: var(--font-weight-bold);
}

/* --- The board ---------------------------------------------------------------------------------
 * Rank, name, figure. The rank is the first thing read, so it is set like a figure; the reader's
 * own row carries an accent rule as well as a tint, because a tint alone cannot carry meaning.
 */
.board-table__rank {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--colour-text-muted);
}

.board-table__name {
    font-weight: var(--font-weight-medium);
}

.board-table__figure {
    font-variant-numeric: tabular-nums;
}

.board-table__row--you {
    background: var(--colour-surface-field);
}

/* ON THE FIRST CELL, NOT ON THE ROW. Blink and WebKit do not paint a box-shadow on a <tr> in a
 * collapsed-border table, so the accent that is supposed to carry "this is you" without relying
 * on the tint alone simply was not drawn. The word "you" and aria-current already carry it;
 * this is the visual half. */
.board-table__row--you > *:first-child {
    box-shadow: inset var(--border-width-accent) 0 0 0 var(--colour-primary);
}

.board-table__row--you .board-table__rank,
.board-table__row--you .board-table__name {
    color: var(--colour-text);
    font-weight: var(--font-weight-bold);
}

/* The competition cards join the panel family: same corner, same hairline, no shadow. */
.competition {
    padding: var(--space-lg);
    border-radius: var(--radius-2xl);
    box-shadow: none;
}

.competition-list {
    gap: var(--space-md);
}

/* ==========================================================================================
 * ADMIN — the same system, a denser page
 * ========================================================================================== */

/* THE FULL-BLEED TRICK, STATED ONCE. These two elements are both the painted surface and the
 * measured row, because the markup gives them no inner wrapper: the padding grows to whatever is
 * left of the viewport beyond the measure, so the ink runs edge to edge while the content stays
 * on the 73rem column. max() keeps the gutter on a phone. */
.adminshell .adminfoot {
    max-width: none;
    padding-inline: max(var(--space-md), (100% - var(--shell-measure)) / 2);
}

.adminshell .adminbar__mark,
.adminshell .adminbar__row {
    max-width: none;
    padding-inline: max(var(--space-md), (100% - var(--shell-measure)) / 2);
}

.adminhead__title {
    font-size: var(--font-size-title);
    letter-spacing: var(--tracking-tight);
    line-height: var(--line-height-display);
}

/* --- The campaign's state, as the page's opening statement ------------------------------------ */
.campstate {
    padding: var(--space-lg);
    border: 0;
    border-radius: var(--radius-2xl);
    background: var(--colour-surface-ink);
    color: var(--colour-text-inverse);
}

.campstate__title {
    color: var(--colour-text-inverse);
    font-size: var(--font-size-2xl);
    letter-spacing: var(--tracking-tight);
}

.campstate__dates {
    color: var(--colour-accent-on-primary);
}

/* --- The four counts, as figures --------------------------------------------------------------
 * They were four boxes of equal weight to everything else on the page. A campaign's size is a
 * fact to be read in one glance, so the numeral is large and the box is gone.
 */
.statrow {
    gap: 0;
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-2xl);
    overflow: hidden;
}

.statcard {
    padding: var(--space-md) var(--space-lg);
    border: 0;
    border-top: var(--border-width) solid var(--colour-border-soft);
    border-radius: 0;
    background: var(--colour-surface);
    box-shadow: none;
}

.statcard:first-child {
    border-top: 0;
}

.statcard__label {
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
}

.statcard__value {
    font-size: var(--font-size-figure);
    line-height: 1;
    letter-spacing: var(--tracking-tight);
    font-variant-numeric: tabular-nums;
}

/* ONE COLUMN, TWO BY TWO, THEN ONE ROW — never the auto-fit mixture the older rule allowed, where
 * a wrapped card kept a left hairline with nothing on its other side.
 *
 * Four tracks arrive only at 64rem. In the tablet band they leave roughly 116px of content box for
 * a figure set in --font-size-figure, and a five-digit count — twenty thousand colleagues is this
 * campaign's own scale — is wider than that with nowhere to break. The card is opaque and the row
 * clips, so the overflow would have been painted over rather than wrapped: an operator would read
 * 20.0 where the count is 20.000. Design review found it by arithmetic; seeded dev counts are too
 * small to show it. */
@media (min-width: 48rem) {
    .statrow {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* The top pair opens the box; the lower pair keeps the rule that separates the two rows. */
    .statcard:nth-child(-n + 2) {
        border-top: 0;
    }

    .statcard:nth-child(even) {
        border-left: var(--border-width) solid var(--colour-border-soft);
    }
}

@media (min-width: 64rem) {
    .statrow {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }

    .statcard {
        border-top: 0;
        border-left: var(--border-width) solid var(--colour-border-soft);
    }

    .statcard:first-child {
        border-left: 0;
    }
}

/* ==========================================================================================
 * THE PUBLIC FRONT — 2026
 *
 * The first thing anybody sees, and the first slide of a demonstration. The bones are the
 * approved Direction A split — photograph on one side, the one action on the other — and what
 * changed is the confidence: an ink bar across the top so the page is framed like the product,
 * a display-sized heading, the facts as a row rather than a bulleted list, and bands underneath
 * that alternate ink and warm sand instead of two pale blues.
 * ========================================================================================== */

.gateshell {
    background: var(--colour-surface-warm);
}

/* --- The split ------------------------------------------------------------------------------ */
@media (min-width: 60rem) {
    .gatesplit {
        grid-template-columns: 42% minmax(0, 1fr);
        grid-template-rows: 1fr;
    }
}

.gatesplit__image {
    min-height: 14rem;
}

@media (min-width: 60rem) {
    .gatesplit__image {
        min-height: 100vh;
    }
}

/* The product's name on the photograph, as a plate in the brand's own blue. */
.gatesplit__plate {
    border-radius: var(--radius-pill);
    padding: var(--space-2xs) var(--space-md);
    font-size: var(--font-size-sm);
    letter-spacing: var(--tracking-caps);
}

.gatesplit__work {
    padding-inline: var(--space-md);
}

.gatesplit__top {
    padding-block: var(--space-sm);
}

/* --- The card the action lives in ----------------------------------------------------------- */
.gatecard {
    max-width: 30rem;
}

.gatecard h1 {
    font-size: var(--font-size-display);
    line-height: var(--line-height-display);
    letter-spacing: var(--tracking-tight);
}

.gatecard__lede {
    margin-top: var(--space-sm);
    font-size: var(--font-size-lg);
    max-width: 30rem;
}

/* A lede carrying an address (the /admin "not an administrator" page): a long one with nowhere to
 * break wraps inside the card rather than scrolling the page sideways at 320, as the check-email
 * screen's address does (.gate__sent-address). */
.gatecard__lede--breaks {
    overflow-wrap: anywhere;
}

.gatecard .button {
    width: 100%;
}

/* THE FACTS, AS A ROW OF THREE. They were a bulleted list, which reads as fine print under a
 * form; as three short facts separated by rules they read as the shape of the campaign. */
.gatecard__steps {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs) var(--space-md);
    margin-top: var(--space-lg);
    padding: var(--space-md) 0 0;
    border-top: var(--border-width) solid var(--colour-border-soft);
    list-style: none;
}

.gatecard__steps li {
    padding: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.gatecard__steps li::before {
    content: none;
}

/* --- The two things a captain asks next, on warm sand --------------------------------------- */

/* The materials page's own bar was here, in this theme and in two more places in this file. It
 * is gone: ACC-001 gave /materials the shared guest header, and nothing in resources/views emits
 * a `publicbar` class any more. Deleted rather than left inert, because a reader searching for
 * "the public bar" would otherwise find a 64px ink bar in the main stylesheet with no way to
 * tell it is dead — which is the confusion this change exists to end. */

.publicfoot {
    background: var(--colour-surface-ink);
    color: var(--colour-text-inverse);
    border: 0;
}

.publicfoot .language__current,
.publicfoot .language__choice {
    color: var(--colour-text-inverse);
}

.publicfoot .language__label,
.publicfoot p {
    color: var(--colour-accent-on-primary);
}

/* A middot rather than a rule between facts: a left border on a wrapped item stands at the
 * start of a line with nothing on its other side, which is the same trap the competition facts
 * fell into. */
.gatecard__steps li + li::before {
    content: '·';
    /* EVERYTHING THE OLD BULLET SET IS UNDONE HERE. It was an absolutely positioned 6px dot
     * pinned to the item's left edge; emptying its content alone left the box in place, and the
     * middot landed on top of the first letter of the second and third facts — on the campaign's
     * front page, directly under the primary action. */
    position: static;
    display: inline;
    width: auto;
    height: auto;
    margin-right: var(--space-2xs);
    background: none;
    border-radius: 0;
    color: var(--colour-border);
}

.gatecard {
    max-width: 34rem;
}

/* The way back for somebody who already has a team: the same one field, said plainly, so
 * signing up and signing in are both obvious without being two different screens. */
.gatecard__return {
    margin: var(--space-md) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* --- Section headings inside an admin screen --------------------------------------------------
 * "Campaign mails" and "Automatic mails" are the divisions of one screen, not the screen's own
 * title, and at the page title's size they competed with it. Small caps: a label for the group
 * below, sitting on a rule.
 */
.adminhead__title--small {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--colour-text-muted);
    padding-bottom: var(--space-2xs);
    border-bottom: var(--border-width) solid var(--colour-border-soft);
}

.adstack__section {
    margin-top: var(--space-xl);
}

/* --- Mail cards -------------------------------------------------------------------------------- */
.mailcard {
    padding: var(--space-lg);
    border: var(--border-width) solid var(--colour-border-soft);
    border-radius: var(--radius-2xl);
    background: var(--colour-surface);
    box-shadow: none;
}

.mailcard__title {
    font-size: var(--font-size-lg);
}

/* Cards in a row end level, and the action sits on the floor of each one: three cards of
 * different text lengths with their buttons at three heights reads as a mistake. */
.mailcards {
    align-items: stretch;
}

.mailcard {
    display: flex;
    flex-direction: column;
}

.mailcard__action {
    margin-top: auto;
    padding-top: var(--space-md);
}

/* The display size belongs to the campaign's front page; a task screen's title is a title. */
.gatecard h1 {
    font-size: var(--font-size-title);
}

/* --- The pager -------------------------------------------------------------------------------- */
.pagenav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2xs) var(--space-md);
    margin-top: var(--space-md);
    padding-top: var(--space-sm);
    border-top: var(--border-width) solid var(--colour-border-soft);
    font-size: var(--font-size-sm);
}

.pagenav__step {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
    padding: 0 var(--space-sm);
    border-radius: var(--radius-pill);
    color: var(--colour-primary);
    font-weight: var(--font-weight-bold);
    text-decoration: none;
}

.pagenav__step:hover,
.pagenav__step:focus-visible {
    background: var(--colour-surface-field);
}

/* Not a link, and it says so without relying on colour: no underline, no hover, muted, and it is
 * a <span> so it is not in the tab order at all. */
.pagenav__step--off {
    color: var(--colour-text-muted);
    font-weight: var(--font-weight-regular);
}

.pagenav__where {
    color: var(--colour-text-muted);
}

/* An error page is one short message: it keeps the reading measure rather than the product's
 * wide column, inside the same frame as everything else. */
.errorshell .page {
    max-width: var(--layout-measure);
}

/* The error shell fills the window, so its footer sits at the bottom of a short page rather than
 * halfway up it. */
.errorshell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.errorshell .page {
    flex: 1 1 auto;
}

/* PANEL PADDING IS A DESKTOP GENEROSITY. At 390px, 32px of padding on each side is 16% of the
 * viewport, and it was enough to push the board's name column narrow enough that
 * overflow-wrap broke colleagues' names mid-word. The phone keeps the smaller step. */
@media (max-width: 47.99rem) {
    .panel,
.adcard,
.roster-panel,
.competition,
.mailcard {
        padding: var(--space-md);
    }

    .board-table__rank {
        font-size: var(--font-size-base);
    }
}

/* A NAME BREAKS ONLY WHEN THE WORD ITSELF DOES NOT FIT. `anywhere` breaks at the narrowest
 * opportunity, so "QA Participant" became "QA Particip / ant" in a phone-width column even though
 * there was a space to break at. `break-word` keeps the space as the first choice and still
 * rescues the single very long name the original rule was written for. */
.board-table__name {
    overflow-wrap: break-word;
}

/* ONE ACTIVE STATE FOR EVERY CHOICE IN A FILTER ROW. The scope row and the "all steps / walked
 * only" row beneath it are the same control asked twice, and they were drawing their chosen
 * option two different ways: an ink pill above, a pale blue tint below. The quiet variant keeps
 * its smaller size and its quieter resting state; when it is the chosen one it is the ink pill,
 * like every other chosen thing in the product. */
.filters__choice--quiet.filters__choice--on {
    background: var(--colour-primary);
    border-color: var(--colour-primary);
    color: var(--colour-text-inverse);
}

/* === MINE SKRIDT, AS THE APPROVED DESIGN DRAWS IT =============================================
 * The composition, the proportions and the order of this screen are a specification rather than a
 * suggestion, and these rules are what makes the implementation match it. Nothing here changes
 * what the screen does: the same three figures, the same two boxes and their arithmetic, the same
 * converter in the same form, the same fourteen days.
 */

/* --- The converter: one flat band inside the panel ------------------------------------------- */
.converter {
    margin-top: var(--space-lg);
    padding: var(--space-lg);
    border: 0;
    border-radius: var(--radius-xl);
    background: var(--colour-surface-field);
}

.converter__title {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.01em;
    text-transform: none;
}

.converter__hint {
    color: var(--colour-text-muted);
    font-size: var(--font-size-base);
}

.converter .field__input,
.converter .field__select {
    background: var(--colour-surface);
}

/* The converter's answer: the equals sign outside the box, the label above the numeral, and the
 * numeral itself the largest thing in the band. */
.converter__result {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: 0;
    border: 0;
    background: transparent;
}

.converter__equals {
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-bold);
    color: var(--colour-text-muted);
}

.converter__result-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-3xs);
}

.converter__result-label {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    color: var(--colour-text-muted);
}

.converter__result-value {
    font-size: var(--font-size-2xl);
    line-height: 1.1;
    letter-spacing: var(--tracking-tight);
    color: var(--colour-primary);
}

/* --- Support: answers beside the way to reach a person --------------------------------------
 * Mobile-first, so one column. The aside moves alongside on a laptop, where the board draws it
 * as a fixed 27.5rem rail against a fluid column of answers.
 */
.helpgrid {
    display: grid;
    /* One column that is the viewport, not its content: an implicit track grew to the dates
     * panel's minimum width, so /support was 322 wide at 320 in Danish. */
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-lg);
}

.helpgrid__answers,
.helpgrid__aside {
    display: grid;
    gap: var(--space-lg);
    align-content: start;
}

/* A small uppercase label above a panel's contents. The panel family had a title but no
 * eyebrow, and the locked design uses the eyebrow on every card that is a category rather
 * than a thing. */
.panel__eyebrow {
    margin: 0 0 var(--space-sm);
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
}

.panel__note {
    margin: 0;
    color: var(--colour-text-muted);
}

/* One question and its answer. Named .helpqa because .qa is already the team-switch page. */
.helpqa {
    display: grid;
    gap: var(--space-md);
}

.helpqa__item + .helpqa__item {
    padding-top: var(--space-md);
    border-top: var(--border-width) solid var(--colour-border-soft);
}

.helpqa__q {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-tight);
}

.helpqa__a {
    margin: var(--space-3xs) 0 0;
    color: var(--colour-text-muted);
    line-height: var(--line-height-base);
}

/* --- The ink panel, as a content card -------------------------------------------------------
 * One True Blue card per screen, carrying the thing the screen is for. Here it is the address.
 */
.inkpanel {
    padding: var(--space-lg);
    border-radius: var(--radius-2xl);
    background: var(--colour-surface-ink);
    color: var(--colour-text-on-primary);
}

.inkpanel__eyebrow {
    margin: 0 0 var(--space-sm);
    color: var(--colour-accent-on-primary);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
}

.inkpanel__address {
    margin: 0;
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-tight);
    overflow-wrap: anywhere;
}

.inkpanel__note {
    margin: var(--space-2xs) 0 0;
    color: var(--colour-text-on-primary-muted);
    line-height: var(--line-height-base);
}

/* --- The campaign's dates, on the tint ---------------------------------------------------------
 * ROSE MEANS INVALID OR FAILED, AND NOTHING HERE IS (ACC-006 decision; ParticipantSupport.dc.html
 * draws #EDF1FA with #D7E1F4 rules). This was the one rose card on the page, which read as a
 * warning about dates that are simply facts. */
.datepanel {
    padding: var(--space-lg);
    border-radius: var(--radius-2xl);
    background: var(--colour-surface-field);
}

.datepanel__eyebrow {
    margin: 0 0 var(--space-sm);
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
}

.datepanel__list {
    margin: 0;
}

.datepanel__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-sm);
    padding: var(--space-2xs) 0;
}

.datepanel__row + .datepanel__row {
    border-top: var(--border-width) solid var(--colour-rule-on-tint);
}

.datepanel__row dt {
    color: var(--colour-text-muted);
}

.datepanel__row dd {
    margin: 0;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

/* --- Wider than a phone --------------------------------------------------------------------- */
@media (min-width: 60rem) {
    .helpgrid {
        grid-template-columns: minmax(0, 1fr) 27.5rem;
        align-items: start;
    }

    /* The four team questions sit two across, as the board draws them. */
    .helpqa--paired {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: var(--space-xl);
    }

    /* Paired items are separated by the column gap, not by a rule across it. */
    .helpqa--paired .helpqa__item + .helpqa__item {
        padding-top: 0;
        border-top: 0;
    }
}

/* The ink panel's own action row, and a button that stands on True Blue. */
.inkpanel__actions {
    margin: var(--space-md) 0 0;
}

.button--onink {
    background: var(--colour-surface);
    color: var(--colour-text);
}

.button--onink:hover,
.button--onink:focus-visible {
    background: var(--colour-text-on-primary-muted);
    color: var(--colour-text);
}

/* --- Inline marks replacing the illustrations ------------------------------------------------
 * The locked design draws no PNG artwork. What is left is a stroke mark beside a fact that is
 * already written out, taking the text colour so it cannot drift from it.
 */
.notecard__icon,
.competition__when-icon {
    flex: 0 0 auto;
    color: var(--colour-text-muted);
}

/* --- Touch targets on a phone ----------------------------------------------------------------
 * The design contract sets 44px, and the locked design's phone boards draw 48. The browser walk
 * found three standalone controls under it: the language choice, the public bar's links and its
 * wordmark, which was 29px because it was sized as a word rather than as a control.
 *
 * INLINE LINKS INSIDE A SENTENCE ARE NOT TOUCHED. WCAG 2.2's target-size rule exempts them, and
 * padding a link in the middle of a paragraph to 48px breaks the line it sits in.
 */
@media (max-width: 47.99rem) {
    .language__choice,
    .language__current {
        display: inline-flex;
        align-items: center;
        min-height: 3rem;
    }
}

/* --- What the browser walk found, at 1440, 1024 and 390 --------------------------------------
 * Standalone controls that were under the contract's 44px, and under the 48 the locked design's
 * phone boards draw. Measured in a real browser rather than reasoned about: sign out was 26px
 * high on every screen because it is styled as a word, and the standings filters were 36.
 *
 * THE DAY INPUTS ARE LEFT AT 40px ON A POINTER DELIBERATELY. The locked design draws the fourteen
 * day cards compact — that is what lets a fortnight fit on one screen — and 40px clears WCAG 2.2
 * AA's target-size minimum of 24px with room to spare. The 44 is this project's own stricter house
 * figure for primary controls, and a grid cell is not one. Below the grid's breakpoint there is no
 * grid: one day fills the screen and its two boxes are the primary controls, so they take the
 * phone figure with everything else.
 */
.link-button {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
}

.filters__choice,
.boardtabs__tab {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
}

@media (max-width: 47.99rem) {
    .link-button,
    .filters__choice,
    .boardtabs__tab,
    .bar__link,
    .navmenu__toggle {
        min-height: 3rem;
    }

    .bar__link,
    .navmenu__toggle {
        display: flex;
        align-items: center;
    }

    /* WRITTEN AT THE SPECIFICITY THAT WINS, AND THAT IS THE WHOLE POINT OF THESE THREE.
     *
     * The list above says 3rem and these three controls stayed at 44, 44 and 36, because each is
     * also described by a rule that outranks a single class: the bar's links through `.appbar`,
     * the quiet filter through its own modifier, and the day boxes through the grid's own
     * definition further up. A phone measurement found them; none of them would have been visible
     * in the source, where the rule above reads as though it already covered them. */
    .appbar .bar__link,
    .adminshell .adminnav__link,
    .filters__choice.filters__choice--quiet {
        min-height: 3rem;
    }
}

/* --- Targets inside the administrative surfaces ------------------------------------------------
 * A browser walk of the seven admin screens at 1440, 1024 and 390 found two shapes under the
 * contract: the attention card's action, and the links in the support tables.
 *
 * THE ACTION TAKES THE HOUSE FIGURE. It is a discrete control sitting alone at the end of a card
 * — the one thing the card asks the reader to do — and 26px was its text height, nothing more.
 *
 * THE SUPPORT TABLE'S LINKS TAKE THE FLOOR, NOT THE HOUSE FIGURE, AND THAT IS A DECISION. A
 * support table is hundreds of dense rows, read on a desk with a pointer; giving every name a
 * 44px box would add a third to the height of a screen whose whole job is to show many records at
 * once. 24px is WCAG 2.2 AA's target-size minimum (2.5.8), the padding widens the hit area beyond
 * the glyphs, and the row itself stays the height the design draws.
 *
 * SCOPED TO THAT TABLE ALONE. The rule named Mit hold's roster too, where the reason does not
 * hold — that one is a participant's screen and is read on a phone. It has no links today, so
 * this narrows an exception rather than changing anything drawn.
 */
.attention__action {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
}

.support__table td a {
    display: inline-flex;
    align-items: center;
    /* BOTH AXES, BECAUSE 2.5.8 MEASURES BOTH. A height alone left a two-letter team name under
     * 24px wide, which is the same failure sideways. */
    min-height: 1.5rem;
    min-width: 1.5rem;
    justify-content: center;
    padding: var(--space-3xs);
}

/* The links that sit beside a button, or alone at the end of a screen, are controls and take the
 * control's height. The one inside the note above the filters is a link in a sentence — WCAG 2.2
 * exempts it, and padding it to 44px would break the line it sits in. */
.support__actions a {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
}

@media (max-width: 47.99rem) {
    .attention__action,
    .support__actions a,
    .pagenav__step {
        min-height: 3rem;
    }

    .pagenav__step {
        display: inline-flex;
        align-items: center;
    }
}

/* ==========================================================================================
 * THE LOCKED BOARDS, MEASURED
 *
 * Everything below is a figure read off the approved Design Overview rather than chosen here.
 * The boards are 1440px canvases with their own gutters, card radii, control heights and type
 * sizes; this section states them, and it is last in the file so it is what the browser uses.
 *
 * WHY IT IS A SECTION AND NOT A REWRITE. The earlier per-screen sections are the product's
 * behaviour — states, errors, empty cases, print, forced colours — and rewriting nine thousand
 * lines to move a radius would risk all of it to change none of it. What the boards specify is
 * geometry and type, and geometry and type are exactly what a last layer can state cleanly.
 *
 * A NOTE ON px. This section uses the boards' own pixel figures rather than converting each to
 * rem, because the comparison that verifies it is a screenshot at 1440 against a board at 1440.
 * The type scale keeps its tokens wherever a token already carries the board's size.
 * ========================================================================================== */

/* --- The shell: 1440 wide, 64px gutters ------------------------------------------------------
 * The measure was 73rem (1168px) centred, so every board's content was 144px narrower than
 * drawn and the three figures never reached the width they are drawn at. The boards put the
 * content between 64px and 1376px of a 1440px page: 1312px of content, and the gutter is the
 * only thing that grows on a wider screen.
 *
 * DESKTOP ONLY, AND THAT BOUND IS LOAD-BEARING. 64px of gutter on a 390px phone leaves 262px of
 * content, and a bar that may not wrap has nowhere to go at 1024 — both of which the browser
 * walk reported as horizontal overflow the moment these figures were applied at every width.
 * The phone and the tablet have boards of their own; these are the 1440 board's numbers.
 */
@media (min-width: 80rem) {
    .appbar__inner,
    .page,
    .shell--wide .page {
        max-width: 90rem;
        padding-inline: 64px;
    }

    /* The public front is drawn on a wider gutter — 96px — and keeps it. */
    .page--public {
        padding-inline: 96px;
    }

    .appbar {
        border-bottom-color: var(--colour-rule-warm);
    }

    /* ONE LINE, NOT TWO. The bar wrapped: the destinations took the slack, the person and the way
     * out fell to a second row, and the board's 84px bar became 130px of chrome above every screen.
     * The nav takes only the room it needs and nothing wraps. */
    .appbar__inner {
        min-height: 84px;
        padding-block: 0;
        gap: 28px;
        flex-wrap: nowrap;
    }

    .appbar .topbar {
        flex: 1 1 auto;
        flex-wrap: nowrap;
        gap: 28px;
        min-height: 84px;
    }

    .appbar .topbar .bar {
        flex: 0 1 auto;
        /* The board sets the destinations two pixels apart. Since 2026-10-04 the D1 block later in
         * the sheet overrides it to --space-2xs at every width this query covers (Kenneth: the
         * current page's pill touched the Admin chip). */
        gap: 2px;
    }

    .appbar .gatemark {
        font-size: 16px;
        font-weight: var(--font-weight-bold);
        letter-spacing: 0.18em;
        white-space: nowrap;
    }

    .appbar .bar__link {
        padding: 11px 16px;
        font-size: 15px;
        font-weight: var(--font-weight-semibold);
        white-space: nowrap;
    }

    .appbar .bar__link[aria-current='page'] {
        font-weight: var(--font-weight-bold);
    }

    /* The person and the way out sit together at the far end, on the same line. */
    .appbar .whoami {
        margin-left: auto;
        gap: 10px;
        align-items: center;
    }

    .appbar .whoami__initials {
        width: 34px;
        height: 34px;
        font-size: 12px;
    }

    .appbar .whoami__name {
        font-size: 15px;
        font-weight: var(--font-weight-semibold);
    }

    .appbar .bar__out {
        margin-left: 18px;
    }

    .appbar .bar__out .link-button {
        font-size: 15px;
        font-weight: var(--font-weight-semibold);
        color: var(--colour-text-muted);
        text-decoration: none;
    }
}

/* --- The page's own rhythm -------------------------------------------------------------------
 * 36px above the first thing, 44px below the last, and 22px between the sections.
 */
.page {
    padding-block: 36px 44px;
}

.pagestack {
    gap: 22px;
}

/* --- Dagens skridt ---------------------------------------------------------------------------
 * A 32px card, two fields and the answer, then the one button that saves the day.
 */
.panel {
    border-radius: 32px;
    border-color: var(--colour-rule-warm);
}

/* --- Konverter aktivitet: one flat band, one row --------------------------------------------- */
.converter {
    margin-top: 26px;
    border-radius: 24px;
    padding: 24px 28px;
    background: var(--colour-surface-field);
    border: 0;
}

.converter__title {
    font-size: 18px;
}

.converter__hint {
    font-size: 15px;
}

.converter__row {
    margin-top: 18px;
    gap: 14px;
}

/* One row, ending in the answer and the button, at the width the board draws it. Narrower than
 * that the controls stack, which is what they did before this section existed. */
@media (min-width: 64rem) {
    .converter__row {
        align-items: flex-end;
    }

    .converter__field--narrow {
        width: 132px;
        flex: 0 0 auto;
    }
}

.converter .field__label {
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    margin-bottom: 8px;
}

.converter .field__select,
.converter .field__withunit {
    height: 56px;
    border-radius: 14px;
    border: 1px solid var(--colour-border-field);
    background: var(--colour-surface);
    font-size: 16px;
    padding: 0 16px;
}

/*
 * THE BOX IS THE WRAPPER, SO THE INPUT INSIDE IT HAS NONE.
 *
 * MySteps.dc.html draws the duration as a span carrying the 1px #6675A3 edge with the number
 * and the word "min" inside it, and sets `border: 0` on the input itself. The wrapper got that
 * treatment above; the input kept an edge of its own, so the field drew a second, paler rounded
 * rectangle inside the real one — visible in a screenshot the moment anybody looked at it.
 *
 * That inner line measured 1.94:1 against the white behind it, which is how F-045 found it. It
 * would have been wrong to repaint it at 4.53:1: the fix for a line that should not exist is
 * not a more visible line. The boundary this control relies on is the wrapper's, which is
 * 4.00:1 on the converter's tint and already clears WCAG 2.2 AA 1.4.11.
 *
 * Focus moves to the wrapper, which owns the boundary (the rule below): the ring is drawn round
 * the field and its unit together, and the input's own outline is taken off.
 */
.converter .field__withunit .field__input {
    border: 0;
    background: none;
    padding: 0;
}

/* The minute control is one composite field: its wrapper owns the visible boundary, so it also
 * owns focus. Leaving the global input outline on the borderless child drew a second inset ring. */
.converter .field__withunit:has(.field__input:focus-visible) {
    outline: var(--focus-ring-width) solid var(--colour-focus);
    outline-offset: var(--focus-ring-offset);
    border-color: var(--colour-primary);
}

.converter .field__withunit .field__input:focus-visible {
    outline: 0;
}

/*
 * AND THE REFUSED STATE MOVES WITH IT.
 *
 * `border: 0` above is (0,3,0) and the product's invalid edge —
 * `.field__input[aria-invalid='true'] { border: 2px solid var(--colour-danger) }` — is (0,2,0),
 * so it lost regardless of order and a refused duration drew no mark at all. Reproduced by
 * submitting "abc": aria-invalid="true", the error sentence rendered, and the input measured
 * `0px none`. Every other refused field in the product marks itself with a 2px Lava Red edge,
 * and SharedStates.dc.html draws it; the one field on the step-entry path that is refused most
 * often was the one that had stopped.
 *
 * On the wrapper, because the wrapper is the box. Restating it on the input would put the mark
 * back on the inner rectangle this change deleted. Found by design review.
 */
.converter .field__withunit:has(.field__input[aria-invalid='true']) {
    border: 2px solid var(--colour-danger);
}

/* THE ANSWER IS NOT A FIELD, SO IT HAS NO FRAME. It sat in a bordered box, which made the one
 * thing on the band that cannot be typed into look like the one thing that can. The board sets
 * it free on the tint, at the size of a figure, beside the button that adds it to the day. */
.converter__result {
    border: 0;
    background: none;
    padding: 0;
    gap: 14px;
    align-items: flex-end;
}

/* The frame lived on the body, which is the element that made the answer look typed into.
 *
 * AND THE 8rem MINIMUM WENT WITH IT. That floor existed so the bordered box was never smaller
 * than a box. The width the answer reserves now is a fixed one (below; 140 on a phone), sized
 * for the largest figure, so the button does not move when a figure arrives. */
.converter__result-body {
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    /* A conversion can reach 279 139 at the permitted duration. Reserve that display width so
     * changing from the empty state to any valid result does not move the add action. */
    flex: 0 0 180px;
    width: 180px;
    min-width: 0;
}

.converter__equals {
    font-size: 28px;
    font-weight: var(--font-weight-bold);
    color: var(--colour-text-arith);
    line-height: 56px;
}

/* IN INK, LIKE THE THREE LABELS BESIDE IT. The board gives "Konverteret" exactly the treatment
 * "Aktivitet", "Varighed" and "Intensitet" get, because it is the fourth thing in the same row
 * and the row reads as one band; muted, it read as a footnote under a number instead.
 *
 * THE COLOUR IS DECLARED HERE RATHER THAN LEFT TO THE RULE THAT SAYS SO 7000 LINES ABOVE. That
 * one loses: this sheet carries four `.converter__result-label` rules and the last one wins per
 * property, so a rule that sets only the size hands the colour back to whichever earlier rule
 * set it last — which was a muted one. Stated here, the winning rule says the whole thing. */
.converter__result-label {
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    color: var(--colour-text);
    margin-bottom: 8px;
}

.converter__result-value {
    display: flex;
    align-items: center;
    height: 56px;
    font-size: 42px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.035em;
    color: var(--colour-text);
    white-space: nowrap;
}

/* The wrapper the phone needs and the laptop does not. See the comment in
 * steps/partials/converter.blade.php for what it is for. */
.converter__answer {
    display: contents;
}

/* THE BAR STAYS ONE LINE FOR A CAPTAIN TOO. The role was a second line under the name, which
 * pushed the destinations onto a row of their own. The board states it on the team's own page,
 * where it belongs, so the bar carries the name alone. */
.appbar .whoami__role {
    display: none;
}

/* Nothing in the bar wraps. The destinations are one row, the way out keeps its two words together
 * and a name is on one line or not drawn — see "A NAME IS WHOLE, ON ONE LINE, OR NOT DRAWN"
 * (F-043). The board's bar is a single 84px line. */
.appbar .topbar .bar,
.appbar .navmenu__panel {
    flex-wrap: nowrap;
}

.appbar .whoami__name,
.appbar .bar__out .link-button,
.appbar .bar__link {
    white-space: nowrap;
}

.appbar .whoami {
    /* A person's name is never shortened (F-043): below 1440 it is not drawn at all — see "A NAME
     * IS WHOLE, ON ONE LINE, OR NOT DRAWN" near the end of the sheet. */
    flex-shrink: 0;
}

/* --- Konkurrencer: four cards two by two, the state at the top of each -----------------------
 * They were three full-width bands with the state pushed out to the right, so the page read as a
 * list of rules. The board sets them as three cards of equal weight, each opening with the state
 * it is in, and the facts on a ruled row along the bottom.
 */
.competition-list {
    display: grid;
    gap: 20px;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Three across on the board this is measured from; one under the other on a phone, which is what
 * the mobile board draws and what the width allows. */
@media (min-width: 64rem) {
    /* Four cards since 29 Sep (Novo's Grand Individual Challenge), so two by two: three columns
     * left the fourth alone on a row, and four made each card too narrow for its two tiles. */
    .competition-list {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.competition-list > li {
    display: flex;
}

.competition {
    flex-direction: column;
    gap: 0;
    width: 100%;
    padding: 28px;
    border-radius: 28px;
    border: 1px solid var(--colour-rule-warm);
}

/* The state comes first, because the first question about a competition is whether it is on. */
.competition__meta {
    order: -1;
    margin: 0 0 16px;
    flex-direction: row;
    align-items: center;
    gap: 12px;
    border: 0;
    padding: 0;
}

.competition__name {
    font-size: 26px;
    letter-spacing: -0.015em;
}

.competition__rule {
    margin-top: 10px;
    font-size: 16px;
    line-height: 1.55;
    color: var(--colour-text-muted);
}

.competition__facts {
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--colour-rule-warm-soft);
    display: flex;
    gap: 24px;
    flex-wrap: wrap;
}

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

.competition__fact-label {
    font-size: 20px;
    font-weight: var(--font-weight-bold);
}

.competition__fact-detail {
    margin-top: 4px;
    font-size: 14px;
    color: var(--colour-text-muted);
}

/* --- Stilling: the board's own table -----------------------------------------------------------
 * The header was a tinted band in sentence case; the board sets it as small caps over a single
 * rule, so the rows below are the only thing with weight.
 */
.board-table thead th {
    background: none;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--colour-rule-warm);
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--colour-text-muted);
}

.board-table tbody td {
    padding: 16px 0;
    border-bottom: 1px solid var(--colour-rule-warm-soft);
}

.board-table__rank {
    font-size: 20px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

.board-table__figure {
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

/* THE READER'S OWN ROW, marked the way the board marks it: the campaign's tint, and a Golden
 * Yellow edge down the left. Yellow is the one palette colour that is not already carrying a
 * meaning on this screen, and it is an edge rather than text, so no contrast threshold applies
 * to it — the row's own tint and the "dig" chip carry the fact without it. */
.board-table__you {
    display: inline-flex;
    align-items: center;
    margin-left: 10px;
    padding: 3px 10px;
    border-radius: var(--radius-pill);
    background: var(--colour-surface);
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    color: var(--colour-text);
}

/* --- What measuring Mine skridt against its board turned up ----------------------------------
 * Every figure below is a measured delta between the board rendered at 1440x2000 and the screen
 * rendered at the same width, not an impression. The pattern behind most of them is one thing:
 * the boards set no line-height, so a 13px label occupies about 15px, while this stylesheet's
 * 1.6 body rhythm made the same label 21px — and eleven of those down a card is why every panel
 * stood taller than the drawing.
 */

/* The panel's own padding: the board draws 34 and 40, and no shadow under a card that is already
 * separated from the ground by a hairline. */
.panel {
    padding: 34px 40px;
    box-shadow: none;
}

/* The header's parts inherited an accent colour and 18px from a rule that lists all three of
 * them together. The board's header is ink at the page's own size; only the eyebrow is smaller,
 * and it sets that itself. */

.appbar .gatemark {
    line-height: 1.2;
}

/* --- The converter's labels -------------------------------------------------------------------
 * Same rhythm as the day's own fields: the board sets the label tight above the control.
 */
.converter .field__label,
.converter__result-label {
    line-height: 1.2;
}

/* --- The day card, at the board's own height -------------------------------------------------
 * 196px, fixed, exactly as the board declares it. The board's own content needs about 201px in
 * that box, and what it does is let flex compress the two inputs from 38px to 33 — so matching
 * the board means taking the same height and the same compression, not a taller card that avoids
 * it. Measured: board 196, implementation was 235.
 */

@media (min-width: 64rem) {
    .converter__row {
        display: flex;
        gap: 14px;
        grid-template-columns: none;
    }

    .converter__field {
        flex: 1 1 auto;
        min-width: 0;
    }
}

/* --- Mit hold, measured against MyTeam.dc.html at 1440x1340 ----------------------------------
 * The board's work area is two columns of 868 and 420 with 24 between them; ours was a grid of
 * 841 and 455 with 16. The roster's card is a little shallower and a little narrower in its
 * padding than Dagens skridt's, and the figures' labels carried the body rhythm again.
 */
@media (min-width: 64rem) {
    .teamwork {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 420px;
        gap: 24px;
        align-items: start;
    }
}

.roster-panel {
    padding: 32px 36px;
}

/* The two columns stand to the same height, as the board draws them, and the cards in the right
 * one are twenty apart. */
@media (min-width: 64rem) {
    .teamwork {
        align-items: stretch;
    }
}

.teamwork > :nth-child(2) {
    gap: 20px;
}

/* --- What the boards set per screen, rather than once -----------------------------------------
 * Measuring five boards side by side showed the card and the title are not one value across the
 * product: Mine skridt's two big forms are the exception, not the rule.
 *
 *   card      MyDetails, ParticipantSupport, Standings   28px radius, 28/30 padding
 *             Mine skridt — Dagens skridt                32px radius, 34/40
 *             Mine skridt — Indtast skridt               32px radius, 32/40
 *             Mit hold — the roster                      32px radius, 32/36
 *   title     Mine skridt, Mit hold                      56px
 *             Stilling, Konkurrencer                     52px
 *             Mine oplysninger, Support                  48px
 *
 * The default was Mine skridt's, applied everywhere, which made every other screen's cards
 * deeper and rounder than drawn. Since 2026-10-05 (the advisor's consistency round) the card is one
 * value again: 20 corners and 24/20 padding, from tokens.css.
 */
.panel {
    padding: var(--card-padding);
    border-radius: var(--radius-2xl);
}

.roster-panel {
    padding: 32px 36px;
    border-radius: 32px;
}

/* --- The guest shell, measured against GuestAuth.dc.html at 1440x900 --------------------------
 * The gate screens are one card on the warm ground between a 64px bar and a 62px ink footer, and
 * every figure below is the board's.
 */
.gatebar {
    min-height: 64px;
}

.gatebar--shared {
    min-height: 88px;
}

@media (min-width: 80rem) {
    .gatebar__inner,
    .gatemain__inner {
        max-width: 90rem;
        padding-inline: 64px;
    }

    /* THE BAR'S GUTTER IS 96 AND THE CARD'S IS 64, which is what Main.dc.html draws and is not
     * a mistake: the bar is chrome running the full width and the card below it is content. It
     * was written as a landing-only override until ACC-001 gave the six guest screens this bar. */
    .gatebar--shared .gatebar__inner {
        padding-inline: 96px;
        min-height: 88px;

        /* 28px between the nav and the pill, which is the gap the boards draw inside the
         * right-hand group; the row's own --space-md is 24. */
        column-gap: 28px;
    }

    /* THE PILL SITS AFTER THE DESTINATIONS, as all three boards draw it. In the markup it comes
     * first, because that is the phone's reading order; one `order` here puts it last on a row
     * wide enough to hold everything. */
    .gatebar--shared .language {
        order: 3;
    }
}

.gatecard {
    padding: 32px;
    border-radius: 28px;
    border-color: var(--colour-rule-warm);
}

.gatecard h1 {
    font-size: 34px;
    letter-spacing: -0.02em;
}

.gatecard__lede {
    margin-top: 10px;
    font-size: 16px;
    line-height: 1.5;
}

/* NO GAP ON THE FORM, BECAUSE THE BOARD PUTS THE SPACE ON THE CHILDREN. GuestAuth.dc.html
 * draws the stack as 24 above the label, 8 above the field and 16 above the button, and the
 * rules below are those three numbers. A container gap of 8 was being added to each of them on
 * top, which is why the sign-in card rendered 361px tall against the board's 340 — a difference
 * no probe of the individual elements could see, because every element was already correct. */
.gate__form {
    row-gap: 0;
}

.gate__form .gate__label {
    margin-top: 24px;
    margin-bottom: 0;
    font-size: 14px;
    /* A ONE-LINE LABEL IS A LABEL, NOT A PARAGRAPH. The body's 1.6 made this 14px label a 22px
     * box where the board draws 16, and because it sits above the field every element below it
     * came down six pixels — the field, the button and the bottom edge of the card. */
    line-height: 1.15;
}

/* THE MESSAGE SITS ABOVE THE FIELD, WITH ITS MARK. GuestAuth.dc.html's VALIDATION card draws
 * the failure between the label and the input — read before the thing it is about, rather than
 * after the reader has already started correcting it — as a 14px line in the board's burnt
 * orange with a 16px warning glyph beside it.
 *
 * #B0562F CARRIES TEXT ON THIS CARD, at 4.98:1 on its white. tokens.css records it at 4.27:1
 * and under the bar, and that is true of the rose ground it is named for, not of white. The
 * glyph repeats the meaning in shape, so nothing here depends on telling the colour (1.4.1). */
.gate__form .field__error,
.profileform .field__error {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-top: 6px;
    margin-bottom: 0;
    font-size: 14px;
    font-weight: 400;
    color: var(--board-negative-text);
}

.field__error-mark {
    flex-shrink: 0;
}

/* AdminEmail.dc.html's placeholder warning: the word stays ink (the base rule) and only the mark
 * takes the warning colour, which is the rule ACC-006 applied on rose. The mark repeats the
 * meaning in shape, so nothing depends on its colour (1.4.1). */
.field__error--marked {
    display: flex;
    gap: 8px;
    align-items: flex-start;
}

.field__error--marked .field__error-mark {
    margin-top: 0.2em;
    color: var(--board-negative-text);
}

/* A WAIT, NOT A MISTAKE: the throttle notice is the sheet's status card (auth/partials/
 * throttle-notice), with no red and no marked field, because nothing was typed wrong. Off a gate
 * card's edge it keeps the card's rhythm above the form. */
.gatecard .throttle-notice {
    margin: 24px 0 0;
}

/* ONE LINE UNDER A HAIRLINE, which is how the board closes a card that has nothing to do. */
.gatecard__foot {
    margin-top: 22px;
    margin-bottom: 0;
    padding-top: 18px;
    border-top: 1px solid var(--board-rule-inner);
    font-size: 15px;
    color: var(--board-text-muted);
}

/* A LINK INSIDE A SENTENCE IS NOT A TARGET WITH A FLOOR, and cannot be given one without
 * damaging the sentence: .text-link is an inline-flex box 44px tall, and in a line of prose it
 * pushes the words around it and stretches the line box — 40px of this card's height and a
 * fifteen-pixel shove of its last line. WCAG 2.2's 2.5.8 carries the exception itself, for a
 * target "in a sentence or [whose] size is otherwise constrained by the line-height of
 * non-target text", which is precisely this one. The colour and the underline stay, and the
 * link keeps its own focus ring; only the box goes. */
.text-link--inline {
    display: inline;
    min-height: 0;
    font-size: inherit;
    font-weight: inherit;
}

.gate__form .field__input {
    margin-top: 8px;
}

.gate__form .button {
    margin-top: 16px;
    letter-spacing: normal;
}

/* Written at the specificity the gate already uses for this label. */
.gatecard .gate__form > .gate__label {
    margin-top: 24px;
    margin-bottom: 0;
    font-size: 14px;
}

/* The mark carries the board's tracking wherever it appears, not only in the application bar.
 * Written against .gateshell because that is the specificity the guest shell already sets it at. */
.gateshell .gatemark,
.gatemark {
    letter-spacing: 0.18em;
}

.gatecard h1 {
    line-height: 1.15;
}

/* The mark the board opens Check your email with: a 48px tile in a pale Light Blue, the glyph
 * drawn in ink. */
.gatecard__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    margin-bottom: 22px;
    border-radius: 14px;
    background: var(--colour-surface-field);
    color: var(--colour-text);
}

/* The state chip above the expired heading. Rose Pink at 25% is the ground the board draws, and
 * the word — not the colour — is what says what happened. */
.gatecard__chip {
    display: inline-flex;
    align-items: center;
    /* The board's chip (GuestAuth .chip, b2 guest pass): 12px words, 5px 10px, 24 tall, 16 above
     * the heading — on the gate cards and on roster-closed alike, one chip. */
    gap: 6px;
    margin: 0 0 16px;
    padding: 5px 10px;
    border-radius: var(--radius-pill);
    background: var(--colour-surface-rose);
    color: var(--colour-text);
    font-size: 12px;
    line-height: 14px;
    font-weight: var(--font-weight-bold);
}

/* A DEADLINE THAT PASSED IS NOT A FAILURE, so its chip is the warm grey the board draws rather
 * than the rose one an expired link gets. */
.gatecard__chip--quiet {
    background: var(--board-quiet-ground);
    color: var(--board-text-muted);
}

.gatecard__chip--quiet .gatecard__chip-dot {
    background: var(--board-quiet-text);
}

.gatecard__chip-dot {
    width: 8px;
    height: 8px;
    border-radius: var(--radius-pill);
    background: var(--colour-danger);
}

/* The heading follows the mark rather than the top of the card. */
.gatecard__icon + h1,
.gatecard__chip + h1 {
    margin-top: 0;
}

/* GuestOnboarding.dc.html sets a 32px heading where GuestAuth.dc.html sets 34, and gives the
 * button 22px of air rather than 16 — the onboarding cards carry more above the action. */
/* --- A FIELD GROUP, FROM GuestOnboarding.dc.html's WELCOME AND CREATE A TEAM CARDS ----------
 *
 * The board draws a group as label → 4 → description → 8 → control, with 24 above the first
 * group and 18 above the next. What was rendering instead was 56 and 56: the group carried a
 * 32px top margin AND its label carried the 24 that belongs to a form whose label is a direct
 * child, the description carried the body's 1.6 and an 8px bottom margin on top of the
 * control's own 8, and the group closed with a 16px bottom margin the board does not draw.
 * Every one of those is a rule that is correct where it was written and wrong stacked.
 */
.gate__form .field {
    margin-top: 18px;
    margin-bottom: 0;
}

.gate__form .field:first-of-type {
    margin-top: 24px;
}

/* The label's own top space belongs to the group now, or it is counted twice. */
.gate__form .field > .gate__label {
    margin-top: 0;
}

.gate__form .gate__hint {
    margin-top: 4px;
    margin-bottom: 0;
    font-size: 14px;
    line-height: 1.5;
}

/* TWO FACTS ON A TILE, from GuestOnboarding.dc.html's INVITATION card: the label quiet on the
 * left, the answer on the right at 400 (audit 1006, D1: key/value values), on the v4 band tint (design v4: #F2F2FA, where the 2026 board
 * laid its pale blue #EDF1FA). A <dl> because that is what two labelled facts are; the rows are <div>
 * so the pairs survive as pairs in a flex layout. */
.factstile {
    margin: 20px 0 0;
    padding: 18px 20px;
    background: var(--colour-surface-band);
    border-radius: 18px;
}

.factstile__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
}

.factstile__row + .factstile__row {
    margin-top: 10px;
}

.factstile dt {
    flex-shrink: 0;
    font-size: 15px;
    color: var(--colour-text-muted);
}

.factstile dd {
    margin: 0;
    font-size: 17px;
    font-weight: var(--font-weight-regular);
    text-align: right;
}

/* THE ANSWER THAT CHANGES SOMETHING GROWS; the one that does not sits beside it at its own
 * width. The board draws the move this way, and the shape says which is which before the words
 * are read. */
.actionrow {
    display: flex;
    gap: 10px;
    margin-top: 16px;
}

.actionrow .button {
    /* width:100% is what the gate gives a button that owns its line; in a row it makes both
     * buttons fight for the same 100% and the primary's words wrap. */
    width: auto;
    flex-grow: 1;
}

.actionrow .button--secondary {
    flex-grow: 0;
    flex-shrink: 0;
    /* A button that owns its line deserves a 12rem floor; one that sits beside another is as
     * wide as its word, which is what the board draws. */
    min-width: 0;
    padding: 0 20px;
}

/* The quiet alternative under a full-width yes, centred as the board centres it. */
.gatecard__alt {
    margin: 12px 0 0;
    text-align: center;
    font-size: 15px;
    font-weight: var(--font-weight-bold);
}

/* The paragraph carries the 12px; the gate's button margin would add 32 more. */
.gatecard__alt .button {
    margin-top: 0;
}

/* The second column stacks: the address that signs somebody in, then which team they are on. */
.profilework__aside {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}

/* --- The editor's language switch, from AdminEmail.dc.html ----------------------------------
 *
 * The board draws it as the segmented pair this product uses everywhere else a choice is
 * exclusive — the standings' two boards, the language card on Mine oplysninger. It was two
 * outlined rectangles, which is the treatment for a row of independent actions rather than for
 * one question with two answers.
 */
.tabs {
    display: inline-flex;
    /* The pair is as wide as its two words. In a stretching parent inline-flex alone does not
     * stop it filling the card, which drew the tint across the whole editor. */
    width: fit-content;
    align-self: flex-start;
    flex-wrap: nowrap;
    gap: 0;
    margin: 0 0 var(--space-md);
    padding: 4px;
    background: var(--board-tint);
    border-radius: var(--radius-pill);
}

.tabs__tab {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0 22px;
    border: 0;
    border-radius: var(--radius-pill);
    color: var(--colour-text-muted);
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    text-decoration: none;
}

.tabs__tab--current {
    background: var(--colour-primary);
    color: var(--colour-text-on-primary);
}

/* --- The campaign's figures on a phone, from MobileFamily.dc.html ----------------------------
 *
 * Four figures are four columns with a hairline between them on a desk. Stacked on a phone the
 * hairlines went with the columns, so a label sat directly under the previous figure's caption
 * and the four ran together as one block of text. The board separates them there too — it draws
 * them as cards of their own — and a rule is the smallest thing that says the same.
 */
@media (max-width: 47.99rem) {
    .statrow .statcard + .statcard {
        margin-top: 16px;
        padding-top: 16px;
        border-top: 1px solid var(--board-rule-inner);
    }
}

/* --- The invitations table on a phone --------------------------------------------------------
 *
 * The roster's phone grid is `1.5rem minmax(0, 1fr) auto` — a number, a name and the actions,
 * which is the shape the members table has. The invitations table has no number column, so its
 * address landed in the 1.5rem track and the state pill was drawn straight through it. Found in
 * the phone screenshot for MobileFamily.dc.html.
 *
 * Its own three rows instead: the address, then the state and the date it was sent, then the two
 * things that can be done about it.
 *
 * AND EVERYWHERE THE ROWS ARE STACKED, NOT ONLY ON A PHONE. This block was written at 47.99rem
 * while the rows themselves stack from 79.999rem, which left the band between them — a small
 * laptop, a landscape tablet — with the invitation address auto-placed into the member grid's
 * 1.5rem number track, wrapping one character per line. The acceptance widths are 320, 390 and
 * 1440, so nothing anybody was measuring would have crossed it.
 */
@media (max-width: 79.999rem) {
    .roster-table--invites .roster-table__row {
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 8px 12px;
    }

    .roster-table__address {
        grid-column: 1 / -1;
        min-width: 0;
        font-size: 15px;
        overflow-wrap: anywhere;
    }

    .roster-table--invites .roster-table__row > td:nth-child(2) {
        grid-column: 1;
    }

    .roster-table__when {
        grid-column: 2;
        text-align: right;
        color: var(--colour-text-muted);
    }

    .roster-table--invites .roster-table__action-cell {
        grid-column: 1 / -1;
    }
}

/* --- Language on Mine oplysninger: a field of the profile form (Kenneth, 2026-09-27) --------
 *
 * Two radios drawn as the segmented pair MyDetails.dc.html shows: the chosen language filled,
 * the other on the tint beside it, each a 48px pill. The radio itself stays in the page, out of
 * sight but focusable, so the keyboard and a screen reader get a real radio group; its focus is
 * drawn on the pill it belongs to.
 */
.langpick {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

/* A legend otherwise sits across the fieldset's top edge, which here is the card's divider line.
 * Floated, it is an ordinary first line inside the fieldset, like the other fields' labels. */
.langpick > legend {
    float: left;
    width: 100%;
    margin: 0;
    padding: 0;
}

.langpick__options {
    display: flex;
    width: fit-content;
    clear: both;
    gap: 0;
    margin-top: 10px;
    padding: 4px;
    background: var(--board-tint);
    border-radius: var(--radius-pill);
}

.langpick__option {
    position: relative;
    display: inline-flex;
}

.langpick__input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.langpick__label {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* 48, the floor Foundations states for a phone and the one this product holds everywhere. */
    min-height: 48px;
    padding: 0 22px;
    border-radius: var(--radius-pill);
    color: var(--colour-text-muted);
    font-size: 15px;
    font-weight: var(--font-weight-bold);
}

.langpick__input:checked + .langpick__label {
    background: var(--colour-primary);
    color: var(--colour-text-on-primary);
}

.langpick__input:not(:checked):hover + .langpick__label {
    color: var(--colour-text);
}

.langpick__input:focus-visible + .langpick__label {
    outline: var(--focus-ring-width) solid var(--colour-focus);
    outline-offset: var(--focus-ring-offset);
}

/* --- The team card on Mine oplysninger, from MyDetails.dc.html ------------------------------ */
.teamcard__name {
    margin: 0;
    font-size: 22px;
    font-weight: var(--font-weight-bold);
    line-height: 1.2;
}

.teamcard__facts {
    margin: 6px 0 0;
    font-size: 15px;
    line-height: 1.5;
    color: var(--board-text-muted);
}

.teamcard__onward {
    margin: 14px 0 0;
    font-size: 15px;
    font-weight: var(--font-weight-bold);
}

/* --- The figures on a phone: NOT two columns, and why ---------------------------------------
 *
 * MyStepsMobile.dc.html sets two compact cards side by side at the top of the screen rather
 * than three full-width ones stacked, and it is right that three stacked cards are most of a
 * 390px first screenful. It was built and reverted: the board's second label is "INDTASTET",
 * one short word, and this product's is "Indtastningsprocent" — a nineteen-character compound
 * with caps tracking on it, which in a half-width track cannot break and pushed the page 45px
 * wider than the phone. A horizontal scrollbar on the main participant screen is a worse
 * failure than a tall column, and the alternatives — breaking a tracked all-caps word across
 * lines, or carrying a second shorter label for one breakpoint — are both worse than the
 * stack. Recorded as a difference, not left as a bug.
 */

/* --- The converter on a phone, from MyStepsMobile.dc.html -----------------------------------
 *
 * The board sets the answer and the button on one row at the foot of the band: "Konverteret
 * 3 240" on the left, "Tilføj" on the right. What rendered instead was the label alone on one
 * line, an equals sign and an em dash on the next, and a full-width button under them — three
 * rows saying what one row says, and an equals sign with nothing on its left to equal.
 */
@media (max-width: 47.99rem) {
    /* THE LAST LINE OF THE BAND, WITH ITS RULE. The board draws the answer and the button on one
     * row under a hairline that crosses the whole band; this is that row. */
    .converter__answer {
        display: flex;
        align-items: flex-end;
        gap: 10px;
        flex: 1 1 100%;
        min-width: 0;

        /* NO MARGIN ABOVE THE RULE, BECAUSE THE ROW ALREADY PUT ONE THERE. The board draws
         * `margin-top: 14px; padding-top: 14px` from the control above — but this is a wrapped
         * flex line inside `.converter__row`, and the row's own `gap: 14px` (set further up this
         * sheet, outside any query, so it is what applies on a phone) is already that first 14.
         * A `margin-top: 14px` on top of it put the band's one structural mark 28px below the
         * controls where the board draws it at 14. Measured after the fix: 14 to the rule and 14
         * from the rule to the answer, which is the board. Found in review. */
        padding-top: 14px;
        border-top: var(--border-width) solid var(--colour-rule-on-tint);

        /* A GUARD NOW, NOT A DEVIATION. This was written when the phone kept the laptop's label,
         * which left about 100px at 320 for a five-digit figure needing 101 and laid the two on
         * top of one another; wrapping was the least-bad answer and was recorded as a board
         * deviation. B2 item 1 removed the cause — the phone takes the board's own `Tilføj` — and
         * `docs/design/visual-acceptance.md` records that exception as closed, so this no longer
         * describes anything the product does at a normal text size.
         *
         * It stays because the constraint it protects against has not gone: a band narrower than
         * 320, or the same band at a text size the participant has enlarged, can still run the
         * figure into the button. Wrapping there is correct and a number drawn through a button
         * never is. Kept as a guard, and said so, because a rule whose comment is out of date is
         * the one somebody deletes as dead. */
        flex-wrap: wrap;
    }

    .converter__result {
        /* The answer asks for its content width and keeps it. It used to ask for zero and take
         * what the button left, which is why "4 615" was drawn as "4 61" with a pill over the
         * rest of it: a flex item with `min-width: 0` and `white-space: nowrap` inside it does
         * not wrap and does not shrink — it overflows, silently. */
        flex: 1 1 auto;
        min-width: min-content;
    }

    /* The equals belongs to the wide row, where the controls are to its left. */
    .converter__equals {
        display: none;
    }

    .converter__result-body {
        flex-basis: 140px;
        width: 140px;
        padding-left: 0;
        background: none;
    }

    /* 12px AND 34px, THE PHONE BOARD'S OWN FIGURES, NOT THE LAPTOP'S SHRUNK. At 42px the answer
     * needed 128px of a 284px band, the button needed the rest and more, and the figure was
     * drawn straight through the button: "4 615" read as "4 61". MyStepsMobile.dc.html sets the
     * label at 12 and the figure at 34, which is what makes the pair fit beside each other. */
    .converter__result-label {
        font-size: 12px;
        margin-bottom: 2px;
    }

    .converter__result-value {
        height: auto;
        font-size: 34px;

        /* The board's 1.1, not the sheet's tight 1.25 — about five pixels of line box on the one
         * screen where the band's height is the constraint. */
        line-height: 1.1;
    }

    /* DURATION AND INTENSITY SHARE A ROW, AS MyStepsMobile.dc.html DRAWS THEM.
     *
     * The board sets the pair in a flex row with a 10px gap, the duration at a fixed 108 and the
     * question growing beside it — `MyStepsMobile.dc.html:83-96`. The product stacked all three
     * controls full width, which was a whole control taller than the board on the one screen the
     * product's own principles call the important one, and item 1 of this brief made the
     * qualifier permanent rather than occasional, so the difference stopped being occasional too.
     *
     * NO BREAKPOINT DECIDES THIS; THE BAND DOES. Both carry a basis and both may grow, so where
     * the band can hold 108 + 10 + 166 they sit side by side at exactly the board's widths, and
     * where it cannot the question wraps and each fills its own line. Choosing a pixel value for
     * that instead would be picking a number the layout already knows. Swept across the phone
     * range: stacked and full width to 380, and at 390 — the board's own canvas — 108 and 166 at
     * x=53 and x=171, which is `MyStepsMobile.dc.html` to the pixel. No squeezed middle state,
     * so there is nothing to stack below.
     *
     * THE BOARD FIXES 108 AND THIS GROWS, WHICH IS A DIFFERENCE WORTH NAMING. The board sets
     * `flex-shrink: 0` on a 390 canvas and draws no other phone width, so it says nothing about
     * 430 or 600. Growing is what the activity select above them already does, and it is what
     * lets the duration fill its own line when the pair wraps — a 108px control alone on a 214px
     * line would read as a mistake. Exact at 390, proportionate above it, full width below.
     *
     * The column gap is the board's 10; the row gap stays 14, because that is what stands between
     * the controls and the hairline below them. */
    .converter__row {
        column-gap: 10px;
    }

    .converter__row .converter__field--narrow {
        flex: 1 1 108px;
    }

    .converter__row .converter__field--qualifier {
        flex: 1 1 166px;
    }
}

/* The save row: the button, and whatever a screen sets beside it, on one line. */
.admin__save {
    display: flex;
    flex-wrap: wrap;
    gap: 12px 20px;
    align-items: center;
}

/* The panel's own rule, set opposite its heading as the board sets it. */
.attention__note {
    margin: -28px 0 20px;
    text-align: right;
    font-size: 15px;
    color: var(--board-text-muted);
}

@media (max-width: 47.99rem) {
    .attention__note {
        margin: 8px 0 16px;
        text-align: left;
    }
}

/* --- Confirming a high figure, from StepsStates.dc.html ------------------------------------
 *
 * The board sets the two components on a tinted panel — label left, number right — because a
 * stray zero is what this screen exists to catch and a number inside a sentence has to be found
 * before it can be checked.
 */
.confirm__split {
    margin: 16px 0 0;
    padding: 16px 20px;
    background: var(--board-tint);
    border-radius: 16px;
}

.confirm__split-row {
    display: flex;
    gap: 16px;
    align-items: baseline;
    justify-content: space-between;
}

.confirm__split-row + .confirm__split-row {
    margin-top: 8px;
}

.confirm__split dt {
    color: var(--board-text-muted);
    font-size: 15px;
}

.confirm__split dd {
    margin: 0;
    font-size: 19px;
    font-weight: var(--font-weight-bold);
}

/* BOTH ANSWERS ARE BUTTONS ON ONE LINE, as the board draws them. The second one wore a link's
 * treatment, which under a full-width primary read as a stray underlined line rather than as
 * the other half of a question. The ordering is unchanged and deliberate: going back to correct
 * comes first, because for somebody who mistyped that is the likelier right answer. */
.confirm__save {
    width: auto;
    min-width: 0;
    padding: 0 24px;
}

@media (min-width: 30rem) {
    .confirm__actions {
        flex-wrap: nowrap;
    }
}

/* THE READER'S OWN ROW CARRIES THE SAME GOLD RULE EVERYWHERE. Standings.dc.html and
 * MyTeam.dc.html both mark it that way, and the standings board was marking it in ink — the
 * same colour as the text beside it, which is not a mark. The word "(dig)" in the cell and the
 * heavier weight carry the meaning; the rule is what finds the row.
 *
 * ON THE FIRST CELL, for the reason recorded where that rule was first written: Blink and
 * WebKit do not paint a box-shadow on a <tr> in a collapsed-border table. */
.board-table__row--you > *:first-child {
    box-shadow: inset var(--border-width-accent) 0 0 0 var(--colour-warning);
}

/* --- The roster, from MyTeam.dc.html -------------------------------------------------------
 *
 * Two lists under one heading each: who is on the team, and who has been asked. The board gives
 * each member an initials mark, marks the reader's own row, and states beside the heading
 * whether the team is large enough to count at all.
 */

/* THE INITIALS ARE A MARK, NOT AN IMAGE: a fixed circle carrying two derived letters, which is
 * what the board draws beside every name. The captain's is filled, so the row that runs the
 * team reads as the row that runs the team without needing the chip to say so twice. */
.roster-table__mark {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-pill);
    background: var(--board-tint);
    color: var(--colour-primary);
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.04em;
}

.roster-table__name {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* A NAME DOES NOT WRAP TO ONE LETTER A LINE. Inside a flex cell the name is a shrinkable item,
 * and in a four-column table it shrank to its longest word and then past it. nowrap on the name
 * is what stops that; the row may wrap the chip onto a second line if the column is genuinely
 * too narrow for both, which is the right thing to give up. */
.roster-table__name {
    flex-wrap: wrap;
}

.roster-table__person {
    white-space: nowrap;
}

/* The name column takes the slack, so the chip sits beside the name rather than under it. */
.roster-table td.roster-table__name {
    width: 100%;
}

/* --- STEPS and ENTERED, from MyTeam.dc.html's two numeric columns ---------------------------
 *
 * RIGHT-ALIGNED BECAUSE THEY ARE READ DOWN. A column of totals is scanned for the largest, and
 * that comparison is only possible when the units line up under each other. Tabular figures are
 * the other half of it: in the proportional face a 1 is narrower than a 0, so `47 020` and
 * `46 865` do not align on their digits without it, and the column reads as ragged.
 *
 * TWO WEIGHTS, AS THE BOARD DRAWS THEM. The steps total is the figure the column exists for, at
 * the name's own size and weight. "4 af 4" beside it is context for that total rather than a
 * second total, so it is a step quieter — the board's 17/700 against 15/muted. The header sits
 * over its own column, which it did not before: both headers were left-aligned above
 * right-aligned figures.
 */
/* QUALIFIED BY `th` DELIBERATELY. `.roster-table th` sets `text-align: left` for every header,
 * and an element-qualified selector outranks a bare class no matter how much later it appears —
 * so the unqualified version of this rule did nothing at all and the two headers stayed left
 * above their right-ranged figures. */
.roster-table th.roster-table__figure-head {
    text-align: right;
}

.roster-table__figure {
    text-align: right;
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* QUALIFIED BY `td` FOR THE SAME REASON THE HEADER IS QUALIFIED BY `th`: `.roster-table td`
 * sets the ink colour, and an element-qualified selector outranks a bare class wherever it
 * sits, so the unqualified rule set the size and silently lost the colour. */
.roster-table td.roster-table__figure--quiet {
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-regular);
}

/* THE LAST COLUMN RANGES RIGHT IN BOTH TABLES, which is the alignment F-012 recorded as
 * differing between them. The board puts ACTION hard against the panel's inner edge in the
 * member table and in the invitations table alike, and the two sit directly above one another. */
.roster-table thead th:last-child,
.roster-table__action-cell {
    text-align: right;
}

/* THE TWO FIGURES ONCE THE ROW STOPS BEING A ROW OF COLUMNS.
 *
 * AFTER THE RULES ABOVE, NOT BESIDE THE OTHER NARROW-WIDTH ROSTER RULES. Those live seven
 * thousand lines earlier, and a media query carries no extra weight — every declaration here
 * would have lost to the desktop block above on source order alone, which is exactly what
 * happened when they were written up there. Same width, same intent, placed where it works.
 *
 * Below this width the row is a three-column grid and every cell in it is placed by hand, so a
 * cell with no placement lands wherever the grid has a gap. These two had none.
 *
 * STEPS TAKES THE THIRD COLUMN, which is where MobileFamily.dc.html puts it: avatar, name, and
 * the total ranged right against the row's end, quiet and small. The slot is free because the
 * status cell that used to hold it is gone.
 *
 * ENTERED TAKES THE SECOND LINE, labelled — and that is a decision rather than a board reading.
 * The phone board draws the total and stops, because a phone row has room for one figure.
 * Dropping the other would take from a captain on a phone the one number that tells them who to
 * chase, so it goes where the activity date used to, in the treatment this file already had for
 * a figure that needs its label to mean anything.
 */
@media (max-width: 79.999rem) {
    .roster-table td.roster-table__figure {
        grid-column: 3;
        grid-row: 1;
        color: var(--colour-text-muted);
        /* 14px, which is the board's own number for this figure on a phone. */
        font-size: 14px;
        font-weight: var(--font-weight-bold);
    }

    /* `td` again, and for the third time in this block's worth of rules: the desktop `--quiet`
     * rule above is qualified, so an unqualified one here loses to it however much later it
     * comes. The two are the same colour, so only the size would have gone wrong — silently. */
    .roster-table td.roster-table__figure--quiet {
        grid-column: 2 / -1;
        grid-row: 2;
        text-align: left;
        font-size: var(--font-size-xs);
        font-weight: var(--font-weight-regular);
    }

    .roster-table__figure--quiet::before {
        content: attr(data-label) ': ';
    }
}

/* THE READER'S OWN ROW, MARKED THE WAY THE BOARD MARKS IT: a tint, and the chip beside the name
 * saying the same thing in words, so nothing depends on the colour.
 *
 * THE YELLOW RULE DOWN THE LEFT IS GONE (ACC-005b item 2). The old board drew a 4px amber edge
 * and this matched it with an inset shadow; ACC-006 redrew the row as tint plus chip and dropped
 * the rule. It was the only place on the page where a warning colour marked something that is
 * not a warning — a captain's own row is the most ordinary thing on the screen — and with the
 * chip already naming it in words the edge was a second, weaker signal in a colour that means
 * something else everywhere else in the product. */
.roster-table__row--you {
    background: var(--board-tint);
}

/* THE BOARD DRAWS THIS CHIP WHITE ON THE TINTED ROW, which is the whole and sufficient reason.
 * Not that it makes the pill visible: white on `--board-tint` is about 1.13:1, against roughly
 * 1.05:1 for the Light Blue 16% it replaces, so both are grounds you have to look for. Nothing
 * depends on either, because the words CAPTAIN · YOU carry the role. */
.roster-table__row--you .roster-table__badge {
    background: var(--colour-surface);
}

/* --- A ROW ACTION IS A QUIET BUTTON (ACC-005b item 3) ---------------------------------------
 *
 * `MyTeam.dc.html` drew all four of them the same until ACC-013: 44px tall, a 1px `#6675A3`
 * edge, the ink word, a 999px radius on white. It now draws Remove and Delete with a transparent
 * edge at `#4D5E93` and keeps the pill for the contextual controls, and the product follows it.
 * "Make captain" is on no row at all any more — it became one line under the roster.
 *
 * THEY USED TO BE TEXT LINKS, AND TWO OF THEM WERE QUIETER THAN THE OTHER TWO. That distinction
 * is gone because the board dropped it — including between "Send a reminder" and "Delete",
 * which is worth saying out loud: a destructive action drawn exactly like a harmless one beside
 * it.
 *
 * WHAT IS ACTUALLY TRUE OF THE THREE, because this used to claim "neither destroys on press,
 * both open a confirmation" and that was wrong about one of them. Remove and Delete each open a
 * confirmation that names the person or the address; the contextual control is a submit button
 * and acts on press, with no confirmation at all.
 *
 * THAT IS NO LONGER ONE RULE IN FOUR PLACES (ACC-013). Remove and Delete are text links and the
 * contextual controls keep the pill, because a row holding two equal-weight pills reads as two
 * equal choices when only one is what a captain came to do. Making the irreversible ones LOOK
 * dangerous is still not the guard — asking first is, and both that destroy something ask.
 *
 * AND A DUPLICATE REMINDER IS NO LONGER SAFE TO PRESS TWICE, because it is no longer possible:
 * one reminder per ask, claimed by a conditional write in TeamInvitation::claimReminder(). The
 * sentence that used to stand here said the opposite and was the reason given for the reminder
 * having no confirmation. The reason still holds; the fact behind it changed.
 *
 * THE EDGE IS `--colour-border-field`, which is what it should always have been. This named
 * `--nn-true-blue-60` directly, under a paragraph explaining that the semantic token still held
 * the retired `#c9d2e4` and that repointing it would reach every field in the product. That was
 * true, and the Foundations token pass did exactly that: the token is `#6675A3` now, the same
 * value this was reaching for, so the workaround has nothing left to work around.
 */
.roster-table__action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0 18px;
    border: var(--border-width) solid var(--colour-border-field);
    border-radius: var(--radius-pill);
    background: var(--colour-surface);
    color: var(--colour-primary);
    font-family: inherit;
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    text-decoration: none;
    cursor: pointer;
}

/* --- The destructive one, quieter (ACC-013) ------------------------------------------------
 *
 * A TEXT LINK, NOT A SECOND PILL. Two pills side by side read as two equal choices; only one
 * of them is what the captain came to do. Remove and Delete are the ways out, so they are
 * drawn as the quieter thing and the contextual action keeps the button.
 *
 * WHAT THIS DOES NOT CHANGE: all three destructive controls still open a confirmation that
 * names the person or the address. The guard is the question, not the paint -- which is the
 * argument the paragraph above makes, and it is untouched by drawing them more quietly.
 *
 * THE TARGET STAYS 44px. min-height survives losing the border and the background, so the
 * activatable box is the same height it was; only the paint is quieter. A text link at its
 * natural 18px would be under the floor `locked-design-system.md` §3 holds, and dropping to
 * it would trade a real accessibility property for a visual one.
 *
 * `--colour-text-muted` is 6.29:1 on white, so the quieter colour is still well above 4.5:1.
 */
.roster-table__action--text {
    border-color: transparent;
    background: none;
    color: var(--colour-text-muted);

    /* The pill's 18px inset is what separated it from its neighbour; without an edge to
     * separate, the word starts where the cell does. */
    padding: 0;
}

.roster-table__action:hover,
.roster-table__action:focus-visible {
    /* The edge darkens rather than the word changing colour: the ink is already the darkest
     * thing in the cell, and an underline on a pill reads as a mistake. */
    border-color: var(--colour-primary);
}

/*
 * AFTER THE RULE IT OVERRIDES, AND THAT ORDER IS THE WHOLE RULE.
 *
 * This block sat ABOVE the one above it. Both selectors are (0,2,0), so source order decides,
 * and the base won: the text link kept its transparent edge at rest and grew an ink pill on
 * hover and on focus -- the treatment this change removed, back exactly when a mouse or a
 * keyboard arrives. Found by design review; confirmed by measuring borderTopColor at rest
 * (rgba(0,0,0,0)) and on hover (rgb(0,25,101)).
 *
 * Third time in this project that a modifier written before its base has quietly lost. If it
 * happens again the answer is a linting rule, not another comment.
 */
.roster-table__action--text:hover,
.roster-table__action--text:focus-visible {
    /* The word underlines and darkens to ink; there is no edge to darken. */
    border-color: transparent;
    color: var(--colour-primary);
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

/* THE TARGET IS THE BUTTON NOW. This used to raise an 18px text link to a 48px box, because the
 * board drew these as plain links and that is under the floor this product holds itself to. The
 * board draws buttons, the rule above states 44px, and the padding makes the width — so the
 * target IS the paint rather than an invisible box around it.
 *
 * 44 IS THE BOARD'S NUMBER AND IT IS NOT THE PHONE'S. This comment used to end "the phone's own
 * floor is met by the row, which is taller than the button inside it", and that was simply not
 * true: a table row is not activatable, so nothing outside the pill contributes to the target.
 * The four row actions were 44px at 390 where `locked-design-system.md` §3 states the floor as
 * "minimum 44px tall, 48px on a phone" and §9 records keeping that floor where a board draws
 * less as an approved accessibility exception. */

/* THE FLOOR RAISES THE TARGET AND LEAVES THE PAINT ALONE, which is the whole of what
 * `locked-design-system.md` §9 approves: "Target floors of 44px (48 on a phone) kept where a
 * board draws less — approved accessibility exception; THE PAINTED APPEARANCE IS PRESERVED."
 *
 * This first went in as `min-height: 48px`, which met the floor by making the pill taller. That
 * is outside the exception — §9 permits a bigger hit area, not a different drawing — so it
 * created an unapproved board/product difference at exactly the widths acceptance measures, and
 * booked it in the disagreement list under a citation that did not cover it. An inset
 * pseudo-element meets the floor with no pixel moved: hit-testing resolves it to its originating
 * element, so the two pixels above and below the pill belong to the control.
 *
 * IT SITS HERE RATHER THAN IN THE NARROW BLOCK SEVEN THOUSAND LINES ABOVE, because a media query
 * carries no specificity: a rule written up there loses to the base rule below it and does
 * nothing at all. The first attempt at this paid for that lesson by painting 44 anyway.
 *
 * BELOW 80rem, which is where the roster is already a stacked layout rather than a row of
 * columns — not "on a phone". The same breakpoint the stacking uses, so the two never disagree
 * about which layout is on screen.
 *
 * 2px EACH WAY, NOT MORE. The stacked actions sit 8px apart, so the extended targets of two
 * neighbours stay 4px clear of one another; a taller reach would let one control's hit area
 * cross into the next, which trades one accessibility failure for a worse one. */
@media (max-width: 79.999rem) {
    .roster-table__action {
        position: relative;
    }

    .roster-table__action::after {
        content: '';
        position: absolute;
        inset: -2px 0;
    }
}

/* --- The invitations, under their own heading ----------------------------------------------- */
.roster-invites {
    margin-top: 28px;
    padding-top: 22px;
    border-top: 1px solid var(--board-rule-inner);
}

.roster-invites__head {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 20px;
    align-items: baseline;
    justify-content: space-between;
    /* The same heading-to-table room as "På holdet" above it (advisor sweep 1): its column heads
     * sat directly under the heading. Measured: 24px there, 0 here. */
    margin-bottom: 24px;
}

.roster-invites__title {
    margin: 0;
    font-size: 20px;
    font-weight: var(--font-weight-bold);
}

.roster-invites__note {
    margin: 0;
    color: var(--board-text-muted);
    font-size: 14px;
    line-height: 1.5;
}

/* A state is a word on a coloured ground, and the ground repeats what the word says. */
.statepill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 5px 12px;
    border-radius: var(--radius-pill);
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    /* A pill that wraps is two pills. The column gives it the width it needs. */
    white-space: nowrap;
}

.statepill__dot {
    width: 7px;
    height: 7px;
    border-radius: var(--radius-pill);
    background: currentcolor;
}

/* Two live asks, one colour, told apart by the WORD -- which is what both boards draw and
 * what CaptainActions' caption says out loud ("Farven alene siger ingenting").
 *
 * ONE RULE, NOT TWO IDENTICAL ONES. These were separate blocks with the same declarations, which
 * is how the next restyle of "Invitation sent" would have changed one and left the other and the
 * two live asks would have stopped being one colour. The selector list states the decision
 * instead of describing it. */
.statepill--invited,
.statepill--reminder_sent {
    background: var(--board-pending-ground);
    color: var(--board-pending-text);
}

.statepill--expired {
    background: var(--board-quiet-ground);
    color: var(--board-text-muted);
}

.statepill--member {
    background: var(--board-positive-ground);
    color: var(--board-positive-text);
}

/* --- Getting colleagues on the team, from MyTeam.dc.html -----------------------------------
 *
 * The board stacks the invitation: a visible label, a line saying what the button does to the
 * person at the other end, a full-width field and a full-width button. The field and the button
 * shared a line, which in a 420px column left the field about as wide as an address is long.
 */

.invite__controls {
    gap: 12px;
    margin-top: 8px;
}

/* Written at two classes so it outranks the 64rem rule that puts them on one line: that rule is
 * right for a wide form and wrong for this column, which is 420px whatever the window is. */
.invite-panel .invite__controls {
    flex-direction: column;
}

/* A HAIRLINE, NOT AN "OR". The second way in is a different thing from the first — a link that
 * never expires and has no state to read — so the board gives it a rule, a heading and a
 * sentence rather than a conjunction. */
.invite__alt {
    margin-top: 22px;
    padding-top: 18px;
    border-top: 1px solid var(--board-rule-inner);
}

.invite__alt-heading {
    margin: 0;
    font-size: 14px;
    font-weight: var(--font-weight-bold);
}

/* The link sits on the board's tint rather than in a white box: it is a value to be read and
 * copied, not a field to be filled. It stays a readonly input so it can still be selected. */
/* THE LINK BOX, AS MyTeam.dc.html DRAWS IT: the tint, a 16px radius, and the URL wrapping inside
 * it rather than scrolling out of a one-line input. `overflow-wrap: anywhere` is the board's own
 * declaration and is what lets a long code break where it must on a 320px phone. */
.invite__linkbox {
    margin-top: 12px;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 16px;
    background: var(--board-tint);
    border-radius: var(--radius-xl);
}

.invite__link {
    flex-grow: 1;
    font-family: inherit;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    color: var(--colour-text);
    overflow-wrap: anywhere;
}

/* Full width, as drawn, and the mark sits with the word rather than beside the box. */
.invite__copy {
    margin-top: 10px;
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
}

/* THE CONFIRMATION STAYS IN THE PAGE WHILE IT IS EMPTY, and that is an accessibility rule
 * rather than a layout preference.
 *
 * It was `:empty { display: none }`, which takes the element out of the accessibility tree
 * altogether — so pressing Copy link both CREATED the live region and filled it in the same
 * frame. A `role="status"` region announces a change to content it was already exposing;
 * one that appears already full is not reliably announced at all, and the failure is silent
 * and only for the readers the criterion was written for. The sighted confirmation appeared
 * either way, which is exactly why reading the CSS was the only way to find it.
 *
 * An empty paragraph with no line box takes no height, so collapsing its margin is all that
 * was ever needed to keep it out of the way. */
.invite__copied:empty {
    margin-top: 0;
}

/* NO TICK MARK, WHERE THE BOARD DRAWS ONE, and this is the reason rather than an omission.
 * The board's confirmation is a tick and "Copied to your clipboard". A tick in the markup is
 * drawn from the moment the page loads, because the region above must stay rendered — so a
 * captain who has pressed nothing would meet a green tick confirming nothing. Recorded in
 * `docs/design/visual-acceptance.md`; the words carry the meaning either way. */
.invite__copied {
    margin: 10px 0 0;
    font-size: var(--font-size-sm);
    color: var(--board-positive-text);
}

/* THE REFUSAL IS NOT DRAWN IN THE SUCCESS COLOUR. This region carries both answers, and the
 * green above belongs to one of them — "Copying is not available here" in the confirmation's own
 * green says the opposite of its own sentence, which is the one thing the design contract asks
 * colour not to do. Ink is the contract's default for text and needs no new colour decision; a
 * red is not reached for, because the palette cannot carry one at 4.5:1 here.
 *
 * AFTER THE RULE IT OVERRIDES, NOT BEFORE IT. One class against one class is a tie, and a tie
 * goes to whichever comes last in the file — written above, this modifier set the colour and the
 * base rule immediately set it back, and the refusal rendered green. Driven, not read. */
.invite__copied--failed {
    color: var(--colour-text);
}

/* --- The lone captain's way out (ACC-010), as one line ---------------------------------------
 *
 * "Created a team by mistake? Delete it and join another." (Novo test feedback 28-29/9). The
 * quietest thing on the page, and deliberately the last: a captain with nobody on their team is
 * here to invite somebody. Muted and small like the handover line under the roster, which is the
 * same kind of thing; the link inside it is the running-text link, so it keeps the sentence's size.
 * 16px above, CaptainActions.dc.html's own number for this line.
 */
.alone-line {
    margin: 16px 0 0;
    font-size: var(--font-size-sm);
    line-height: 1.5;
    color: var(--colour-text-muted);
}

/* The way out is bold, as the board draws it and as the handover line's link is. */
.alone-line .text-link--inline {
    font-weight: var(--font-weight-bold);
}

/* --- The handover, as one line under the members table -------------------------------------
 *
 * Quiet and after the table, like the delete control on the empty-roster panel: a captain is
 * on this page to see their team, not to stop being its captain. Same 16px the alone line
 * has above it, because they are the same kind of thing in the same place.
 *
 * MUTED, NOT INK. It is a way out rather than a thing to do -- the panel above it is what the
 * page is for -- and the muted colour is what MyTeam.dc.html gives every quiet word.
 */
.roster__handover {
    /* 3px, not 16: the quiet link inside is 44 tall to make its target (.quietlink), so the gap a
     * reader sees is still the 16px the alone line has above it. */
    margin: 3px 0 0;
    font-size: var(--font-size-sm);
}

/* --- Choosing a successor -------------------------------------------------------------------
 *
 * A LIST OF PEOPLE, drawn as a list. No radio group: picking here opens the confirmation for
 * that person rather than setting a value, so each name is a link and the page has no form.
 *
 * 44px MINIMUM, because every one of these is a tap target on a phone and the list is the only
 * thing on the screen. The padding does the work rather than a height, so a long name that
 * wraps grows the row instead of overflowing it.
 */
.handover {
    margin: var(--space-md) 0 0;
    padding: 0;
    list-style: none;
    border-top: 1px solid var(--colour-rule-warm);
}

.handover__item {
    border-bottom: 1px solid var(--colour-rule-warm);
}

.handover__choice {
    display: block;
    padding: 13px 0;
    min-height: 44px;
    box-sizing: border-box;
    color: var(--colour-text);
    font-weight: var(--font-weight-bold);
    text-decoration: none;
}

.handover__choice:hover,
.handover__choice:focus-visible {
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

/* --- The roster deadline, from MyTeam.dc.html's ink card -----------------------------------
 *
 * The board gives the deadline the only ink panel in the column, which is how it says this is
 * the one date on the page. It was a white panel like the two around it, and a captain reading
 * down the column met three of the same thing.
 */
.deadline-panel {
    display: block;
    padding: 24px;
    background: var(--colour-primary);
    border: 0;
    border-radius: 20px;
}

.deadline-panel__date {
    margin: 0;
    color: var(--colour-text-on-primary);
    font-size: 26px;
    font-weight: var(--font-weight-bold);
    line-height: 1.15;
    letter-spacing: -0.01em;
}

/* The exact moment reads as part of the date, not as a footnote to it. */
.deadline-panel__note:first-of-type {
    margin-top: 4px;
    color: var(--colour-text-on-primary);
    font-size: 17px;
    font-weight: var(--font-weight-bold);
}

.deadline-panel__note {
    margin: 12px 0 0;
    color: var(--board-on-ink-muted);
    font-size: 15px;
    line-height: 1.5;
}

/* WHERE THE TEAM COUNTS, AS ONE GROUP. GuestOnboarding.dc.html draws the two placement
 * questions as a heading, a line saying what the answer is for, and then two narrow selects side
 * by side — one question, not two more. They were rendering as two full-width fields with
 * nothing tying them together. */
.placegroup {
    margin-top: 20px;
}

.placegroup__title {
    margin: 0;
    font-size: 14px;
    font-weight: var(--font-weight-bold);
}

.placegroup__note {
    margin: 4px 0 0;
    font-size: 14px;
    line-height: 1.5;
    color: var(--board-text-muted);
}

.placegroup__fields {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
    margin-top: 10px;
}

/* The group owns the space above it, so neither column starts with its own. */
.placegroup__fields .field,
.placegroup__fields .field:first-of-type {
    margin-top: 0;
}

/* A column label is smaller and quieter than a question's own: it names a box, not a question. */
.placegroup__fields .gate__label {
    font-size: 13px;
    color: var(--board-text-muted);
}

/* TWO COLUMNS NEED THE WIDTH FOR TWO. Below the gate card's comfortable width the selects would
 * be narrower than the country names in them, so they stack — the group still reads as one
 * question, because the heading and the line above it are what say so. */
@media (max-width: 30rem) {
    .placegroup__fields {
        grid-template-columns: minmax(0, 1fr);
    }
}

.gatecard--onboarding h1 {
    font-size: 32px;
    letter-spacing: -0.02em;
}

.gatecard--onboarding .gate__form .button {
    margin-top: 22px;
}

/* --- The public front, measured against GuestMaterials.dc.html at 1440x1460 -------------------
 * The board puts this family on the same 1440 canvas as every other screen, with the bar 64px
 * tall and everything between 64 and 1376. It was a 64rem column centred in the page, which put
 * the brand at 224 rather than 64 and made the heading a third smaller than drawn.
 */
@media (min-width: 80rem) {
    .matshead__inner,
    .publicfoot__inner {
        max-width: 90rem;
        padding-inline: 64px;
    }
}

.matshead__heading {
    font-size: 48px;
    line-height: 1;
    letter-spacing: -0.03em;
}

.matshead__lede {
    margin-top: 14px;
    margin-bottom: 0;
    max-width: 620px;
    font-size: 18px;
    line-height: 1.55;
}

/* --- The error and outage states, measured against GuestMaterials.dc.html --------------------
 * The board draws them as four cards side by side — a spec sheet rather than a page — and what
 * it specifies is what is inside one: a 24px card with 26px of padding, a 22px heading and a
 * 15px line under it. The product shows one of them at a time, in its own column.
 */
.message {
    padding: 26px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 24px;
    background: var(--colour-surface);
}

/* THE STATE, ABOVE THE SENTENCE. GuestMaterials.dc.html draws every error card with a small
 * tracked line naming what happened — 404, 419 · PAGE EXPIRED — before the words explaining it.
 * Uppercased here rather than in the language files so each string stays a sentence a
 * translator can read, and because Danish and English capitalise differently. */
.message__code {
    margin: 0 0 12px;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--board-text-muted);
}

.message__heading {
    font-size: 22px;
    line-height: 1.2;
    letter-spacing: -0.015em;
}

.message__body {
    margin-top: 8px;
    font-size: 15px;
    line-height: 1.5;
}

.message .button {
    margin-top: 16px;
    width: auto;
    padding: 0 24px;
}

/* --- The landing, measured against Main.dc.html at 1440x1700 ---------------------------------
 * This board is its own screen and its figures are not the sign-in family's: an 88px bar on a
 * 96px gutter, a display headline, and "Three steps" set in ink on the warm ground rather than
 * white on a band.
 */
/* The bar's own 88px and 96px gutter moved to `.gatebar` under ACC-001; what is left here is
 * landing-only, because the hero and the how-it-works band share the bar's wider gutter and the
 * gate card does not. */
@media (min-width: 80rem) {
    .gateshell--landing .gatemain__inner {
        padding-inline: 96px;
    }
}

.gatecard--landing h1 {
    margin-top: 20px;
    font-size: 82px;
    line-height: 0.95;
    letter-spacing: -0.035em;
}

.gatecard--landing .gatecard__lede {
    margin-top: 24px;
    font-size: 20px;
}

/* The eyebrow the board sets over the landing's headline. */
.gatecard__eyebrow {
    margin: 0;
    font-size: 12px;
    line-height: 1.2;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--colour-text-muted);
}

/* --- Stilling, measured against Standings.dc.html at 1440x1180 -------------------------------
 * The board panel is the deepest card on any participant screen — 32px round, 30 by 36 — and
 * the scope pills sit in a 5px trough rather than a bordered pair.
 */
.board-panel {
    padding: 30px 36px;
    border-radius: 32px;
}

/* WHAT THIS BOARD SHOWS, under the tabs (ACC-007 item 7). `Standings.dc.html` draws it at 15px
 * on a 1.5 line, in the muted ink, 16px under the row of controls — which is the same line the
 * other panels' ledes are set on, so it takes the board's numbers rather than a new size. */
.board-panel__lede {
    margin: var(--space-sm) 0 0;
    color: var(--colour-text-muted);

    /* The token, not the 15px it resolves to: a literal px ignores a raised browser default. */
    font-size: var(--font-size-sm);
    line-height: 1.5;
}

.boardtabs {
    display: inline-flex;
    gap: 4px;
    padding: 5px;
    border: 0;
    background: var(--colour-surface-field);
    border-radius: var(--radius-pill);
}

.boardtabs__tab {
    padding: 11px 22px;
    font-size: 15px;
}

/* The footnote is the panel's last line and takes its air above rather than below. */
.board-table__note {
    margin-top: 0;
    padding-top: 20px;
}

/* --- Konkurrencer, measured against Competitions.dc.html at 1440x1160 ------------------------ */
/* The state pill: 13px on a pale green, with its own darker green for the word. Forest Green at
 * 15% is the ground and the text is the same colour taken to 4.9:1 on it — the palette's own
 * tint model doing what the board's drawn pair does. */
.competition__state {
    padding: 6px 14px;
    font-size: 13px;
}

.competition__name {
    margin-top: 16px;
}

/* --- Mine oplysninger, measured against MyDetails.dc.html at 1440x1060 -----------------------
 * The form is the one card on this screen with the deeper treatment; the side cards keep the
 * 28px default the board sets for every other panel.
 */
.details-panel {
    padding: 32px 36px;
    border-radius: 32px;
}

.details-panel .field__input,
.details-panel .field__select {
    margin-top: 8px;
}

.details-panel .button {
    margin-top: 26px;
    letter-spacing: normal;
}

/* Two columns at the width the board draws them, and one below it — a 440px sidebar next to a
 * 390px phone is 440px of horizontal scroll. */
@media (min-width: 64rem) {
    .helpgrid {
        grid-template-columns: minmax(0, 1fr) 440px;
        gap: 24px;
    }
}

.helpqa__q {
    letter-spacing: -0.01em;
}

.helpqa__a {
    margin-top: 8px;
    font-size: 15px;
}

.inkpanel {
    padding: 30px;
    border-radius: 28px;
}

.datepanel {
    padding: 26px 30px;
    border-radius: 28px;
}

/* --- The shared parts, measured against SharedStates.dc.html at 1440x1180 --------------------
 * This board is the component sheet: one answer per situation, used everywhere. The per-screen
 * boards override these where they say something different — Mine skridt's 80px boxes, the gate's
 * 56 — and everything that does not is this.
 */
.field__input,
.field__select {
    height: var(--control-height);
    padding: 0 var(--control-padding);
    font-size: 16px;
    border: 1px solid var(--colour-border-field);
    border-radius: var(--control-radius);
}

.field__input[aria-invalid='true'] {
    border: 2px solid var(--colour-danger);
}

/* Item 12: visibly not available - the band tint, the muted value, and the cursor says so. */
.field__input:disabled,
.field__select:disabled {
    color: var(--colour-text-muted);
    background-color: var(--colour-surface-band);
    border: 1px solid var(--colour-rule-warm);
    cursor: not-allowed;
}

/* A rule in the status colour down the left, and the words carrying the meaning. */
.status {
    padding: 14px 16px;
    border: 0;
    border-left: 4px solid var(--colour-accent-on-surface);
    border-radius: 0 14px 14px 0;
}

.status__title {
    margin: 0;
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    line-height: 1.4;
}

.status--success {
    border-left-color: var(--nn-forest-green);
}

.status--error {
    border-left-color: var(--colour-danger);
}

.status--warning {
    border-left-color: var(--colour-warning);
}

/* THE REJECTED FIELD KEEPS ITS RED EDGE on the gate too. Lava Red is 3.66:1, a border's
 * threshold and not text's; the message above carries the words. (The gate's field once rested on
 * a 2px ink edge, which this rule had to outrank; item 12 gives every field the one quiet edge.) */
.gate__form .field__input[aria-invalid='true'] {
    border-color: var(--colour-danger);
}

/* ==========================================================================================
 * ADMINISTRATION, MEASURED AGAINST AdminOverview.dc.html AND Support.dc.html
 *
 * Both boards are 1440x1120 and draw the same shell: an eighty-pixel ink bar on one line,
 * sixty-four-pixel gutters, and the work in white panels on the warm ground. The figures below
 * are theirs. Where a value has no palette behind it, the note says what stands in for it.
 * ========================================================================================== */

/* --- The bar ------------------------------------------------------------------------------- */
.adminshell .adminbar {
    padding: 0;
}

.adminshell .adminbar__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2xs) var(--space-sm);
    max-width: none;
    padding-inline: max(var(--space-md), (100% - var(--shell-measure)) / 2);
    padding-block: var(--space-2xs);
}

.adminshell .adminbar__mark {
    /* margin: 0 too, not only the width: the shell rule it is overriding sets `margin: 0 auto`,
     * and an auto left margin on a flex line quietly centres the mark twenty-five pixels off the
     * gutter the board puts it on. */
    width: auto;
    max-width: none;
    margin: 0;
    padding: 0;
    min-height: 0;
    gap: 12px;
    align-items: baseline;
}

/* ONE LINE, AND ONLY WHERE THE LINE FITS. The boards are 1440 canvases, and the bar they draw is
 * a single eighty-pixel row: the mark, then the navigation, then the operator at the far edge.
 * Applied at every width it was a row that could not wrap, so at 1024 it pushed the page 116px
 * wider than the viewport and at 390 it pushed it 735 — the whole administration family scrolled
 * sideways. Below the board's own width the bar wraps as it did before. */
@media (min-width: 80rem) {
    .adminshell .adminbar,
    .adminshell .adminbar__inner {
        min-height: 80px;
    }

    .adminshell .adminbar__inner {
        flex-wrap: nowrap;
        gap: 0;
        padding-block: 0;
    }

    /* Thirty-four between the mark and the first destination, and the operator pushed to the far
     * edge — two different gaps on one flex line, so the right-hand group takes the space rather
     * than a single gap splitting the difference. The mark carried the shell's own
     * width:100%/max-width centring, which on one flex line made it a 755px item that shrank the
     * navigation into three wrapped rows; here it is as wide as the two words in it. */
    .adminshell .adminbar__mark {
        flex-shrink: 0;
        margin-right: 34px;
    }

    .adminshell .adminnav {
        flex-wrap: nowrap;
    }
}

.adminshell .adminbar__product {
    font-size: 16px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.18em;
}

.adminshell .adminbar__section {
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.18em;
}

.adminshell .adminbar__row {
    display: contents;
}

.adminshell .adminnav {
    gap: 2px;
}

.adminshell .adminnav__link {
    padding: 10px 16px;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    border-radius: var(--radius-pill);
}

.adminshell .adminnav__link--on {
    font-weight: var(--font-weight-bold);
}

.adminshell .adminbar__who {
    margin-left: auto;
    gap: 18px;
    align-items: center;
}

/* A chip, not a line of text: board padding 7/14 on the raised ink step. */
.adminshell .adminbar__role {
    margin: 0;
    padding: 7px 14px;
    border-radius: var(--radius-pill);
    background: var(--colour-surface-ink-raised);
    color: var(--colour-text-inverse);
    font-size: 13px;
    font-weight: var(--font-weight-bold);
}

/* --- The QA contexts, from SuperOps.dc.html --------------------------------------------------
 *
 * The board sets the four synthetic positions as a two-by-two grid of buttons, which is the
 * whole switch in one glance. They were four full-width cards stacked down the page, so
 * choosing the fourth meant scrolling past three. The descriptions stay — the board has none,
 * but "opens My steps" is the thing an operator wants before pressing, not after.
 */
@media (min-width: 40rem) {
    .qa__list {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 16px;
    }

    .qa__item {
        margin: 0;
    }
}

.adminshell .adminbar__name {
    margin: 0;
    font-size: 15px;
    color: var(--colour-text-on-primary-muted);
}

.adminshell .adminbar__out .link-button {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--colour-text-inverse);
}

/* --- The page ------------------------------------------------------------------------------ */
.adminshell .adminmain {
    max-width: none;
    padding-inline: max(var(--space-md), (100% - var(--shell-measure)) / 2);
}

@media (min-width: 80rem) {
    /* Sixty-four-pixel gutters on a 1440 canvas, which is what both boards draw — the shell
     * measure is narrower than that and left the work floating in the middle of the page. */
    .adminshell .adminbar__inner,
    .adminshell .adminmain,
    .adminshell .adminfoot {
        max-width: 90rem;
        padding-inline: 64px;
    }
}

.adminshell .adminmain {
    padding-block: 36px 40px;
}

.adstack {
    gap: 22px;
}

/* --- The heading ------------------------------------------------------------------------------ */
.adminhead__title {
    font-size: 48px;
    line-height: 1;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
}

.campstate__dates {
    margin: 0;
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    color: var(--colour-text);
}

/* --- The panels ----------------------------------------------------------------------------- */
.adcard {
    padding: 30px 36px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 32px;
    background: var(--colour-surface);
    box-shadow: none;
}

.adcard__title {
    font-size: 24px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
    line-height: 1.2;
}

.adcard__eyebrow {
    margin: 0;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--colour-text-muted);
}

.adcard--ink {
    border: 0;
    background: var(--colour-surface-ink);
    color: var(--colour-text-inverse);
    padding: 30px;
}

.adcard--ink .adcard__eyebrow {
    color: var(--colour-accent-on-primary);
}

.adcard--ink .adcard__lede,
.adcard--ink .nextmail__name {
    color: var(--colour-text-on-primary-muted);
}

.adcard--ink .nextmail__name {
    color: var(--colour-text-inverse);
}

/* The ink ground swallows a True Blue ring, so the one on it is white. */
.adcard--ink :focus-visible {
    outline-color: var(--colour-text-inverse);
}

/* --- Needs attention ------------------------------------------------------------------------ */
.attention__row {
    gap: 18px;
    padding: 18px 0;
    border-bottom: 1px solid var(--colour-rule-warm-soft);
}

.attention__row:last-child {
    border-bottom: 0;
}

.attention__what--strong {
    font-size: 18px;
    font-weight: var(--font-weight-bold);
}

.attention__action {
    flex-shrink: 0;
    font-size: 15px;
    font-weight: var(--font-weight-bold);
}

.campfigures {
    flex-grow: 1;
    min-width: 0;
}

/* --- The four figures, as columns inside their panel ---------------------------------------- */
.statrow {
    margin-top: 24px;
    border: 0;
    border-radius: 0;
    overflow: visible;
    gap: 0;
}

.statcard {
    padding: 0 24px;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
}

.statcard__label {
    font-size: 11px;
    letter-spacing: 0.16em;
}

.statcard__value {
    margin-top: 12px;
    font-size: 44px;
    line-height: 1;
    letter-spacing: -0.035em;
}

.statcard__note {
    margin-top: 10px;
    font-size: 14px;
    color: var(--colour-text-muted);
}

@media (min-width: 64rem) {
    .statcard {
        border-left: 1px solid var(--colour-rule-warm);
    }

    .statcard:first-child {
        border-left: 0;
        padding-left: 0;
    }

    .statcard:last-child {
        padding-right: 0;
    }
}

/* --- What the first measurement against the two boards found --------------------------------- */

/* ADMINISTRATION IS LIGHT BLUE, NOT WHITE, and a destination nobody is on is the quiet tint. The
 * blanket "everything in the bar is white" rule flattened the three voices the boards draw into
 * one. The mark, the current destination and Sign out stay white; these two step back. */
.adminshell .adminbar__section {
    color: var(--colour-accent-on-primary);
}

.adminshell .adminnav__link {
    color: var(--colour-text-on-primary-muted);
}

.adminshell .adminnav__link--on,
.adminshell .adminnav__link[aria-current='page'] {
    color: var(--colour-text);
}

.attention__row {
    align-items: center;
}

.statcard__value {
    margin-bottom: 0;
}

/* --- Users & support, measured against Support.dc.html --------------------------------------- */

/* THE SEARCH IS THE WIDTH OF THE PAGE. It used to sit inside the left column, above the table,
 * which made the one control the screen exists for narrower than the results it produces. The
 * board gives it its own panel across the full measure, with the field, the note about the
 * address bar and the action on one line. */
.supportsearch {
    padding: 24px 28px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 28px;
    background: var(--colour-surface);
}

.supportsearch__row {
    flex-wrap: nowrap;
    align-items: center;
    gap: 16px;
}

.supportsearch__row .button {
    flex-shrink: 0;
    width: auto;
    padding: 0 30px;
}

@media (min-width: 64rem) {
    /* 806 and 482 on a 1312 measure, which is what the board draws: the case notes get the
     * width they need and the table keeps the rest. */
    .supportwork {
        grid-template-columns: minmax(0, 1fr) 482px;
        gap: 24px;
    }
}

.supporttable {
    padding: 30px 34px;
    border-radius: 32px;
}

.selectedcard {
    padding: 30px;
    border-radius: 32px;
}

/* --- The rest of the administration family ---------------------------------------------------
 *
 * AdminEmail.dc.html and AdminCampaign.dc.html set their page title at 44 rather than the 48 the
 * overview and the support screen use, and give a section inside a panel 20. The single
 * .adminhead__title figure above was swallowing the --small modifier and setting every group
 * heading on the e-mail index at page-title size.
 */
.adminhead__title--small {
    font-size: 20px;
    line-height: 1.2;
    letter-spacing: -0.015em;
}

/* The e-mail centre's title, which its board sets four pixels below the overview's. */
.adminhead--compact .adminhead__title {
    font-size: 44px;
}

/* --- The template list, and the campaign form ------------------------------------------------ */

/* A LABEL AND ITS FIELD, as both boards draw them: the label at 14/700 directly above a 54px box
 * with a 16px radius. The component sheet's 50px field is the one on a participant screen; an
 * administration form states its own. */
.adminshell .field__label,
.adminshell .field > label {
    font-size: 14px;
    font-weight: var(--font-weight-bold);
}

.adminshell .field__input,
.adminshell .field__select {
    height: 54px;
    padding: 0 16px;
    border-radius: 16px;
}

.adminshell textarea.field__input {
    height: auto;
    padding: 14px 16px;
    line-height: 1.55;
}

/* The field the screen is for takes the ink edge; the rest take the hairline. */
.adminshell .field--primary .field__input {
    border: 2px solid var(--colour-primary);
}

/* --- The secondary administration screens ----------------------------------------------------
 *
 * Campaign settings, identity, finalise, the competition draw, the support sub-pages and test
 * access were built on .admin/.support rather than the .adstack the overview uses, so they kept a
 * 46rem column centred in the middle of a 1312px page with the form as bare markup on the ground.
 * AdminCampaign.dc.html draws the same work as a panel on the left of the measure. These are its
 * figures; the markup inside each form is untouched.
 */
.adminshell .admin,
.adminshell .support {
    max-width: 868px;
    margin-inline: 0;
}

/* A record is a table, and a table is not held to a form's measure. Nor is the participant
 * record, which SuperRecords.dc.html draws as two columns across the whole work area. */
.adminshell .support--wide {
    max-width: none;
}

/* A form on a wide page still sits on the form measure. Test access holds two tables and one
 * form; the form stretched to 1312px was a two-field form with a line of empty field after each
 * address (findings 2026-09-22, Testadgang). The same 868px as `.adminshell .support` above:
 * change them together. */
.adminshell .support--wide .support__section--form {
    max-width: 868px;
}

.adminshell .support__heading {
    font-size: 44px;
    line-height: 1;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
}

.adminshell .admin__header .lede,
.adminshell .support__lede {
    margin-top: 12px;
    font-size: 18px;
    color: var(--colour-text-muted);
}

.adminshell .admin__form {
    margin-top: 22px;
    padding: 32px 36px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 32px;
    background: var(--colour-surface);
}

.adminshell .admin__section {
    margin-top: 20px;
    padding: 28px 32px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 28px;
    background: var(--colour-surface);
}

/* THE HISTORY BESIDE THE FORM (AdminCampaign.dc.html): the settings in the wide column and what
 * changed in 420px at their side, top-aligned, from 64rem; stacked, as before, below that. */
.adminshell .admin--split {
    max-width: none;
}

@media (min-width: 64rem) {
    .adminshell .admin--split {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 420px;
        gap: 24px;
        align-items: start;
    }

    .adminshell .admin--split > .admin__aside {
        margin-top: 0;
    }
}

.admin__main {
    min-width: 0;
}

/* A fieldset's default minimum is its content's width, so the date-and-time inputs held the form
 * 2px wider than a 390px screen. Administration is designed for the desktop; below 1024 it must
 * still not scroll sideways. */
.adminshell .admin__group {
    min-width: 0;
}

/* NO SELECT RULE ON THE ADMIN FORM ANY MORE, and none of its states either.
 *
 * This said the timezone select "also carries the sign-in gate's select class, whose 2px pale
 * edge made it the one field unlike its neighbours". That pale edge was `select.field__input` in
 * the base rule, and it is gone — so the hairline this carried by hand is now what every select
 * in the product inherits. The two state rules under it existed only to claw back what its own
 * extra specificity had taken: `:focus-visible` restoring the primary colour that
 * `.field__input, .field__select:focus-visible` already gives, and `[aria-invalid='true']`
 * restoring the 2px danger edge that `.field__input[aria-invalid='true']` already gives.
 *
 * Removed rather than kept as harmless. Three element-qualified rules are the next specificity
 * trap, and a future edit to the shared select edge would silently not reach `/admin/campaign`.
 * Driven in all three states — resting, focused and refused — before this was kept, because a
 * specificity reading is exactly what got the gate rule wrong earlier in this same change. */

.adminshell .admin__heading {
    font-size: 20px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
}

/* A GROUP IS A QUIET PANEL, NOT A BOXED FIELDSET. AdminCampaign.dc.html draws a block of related
 * settings as a tinted card with its name as an ordinary label on top — the browser's own
 * fieldset frame, with the legend notched into its edge, is a shape nothing else on these screens
 * uses. */
.adminshell .admin__group {
    margin: 0 0 20px;
    padding: 18px 20px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 18px;
    background: var(--colour-surface-warm);
}

/* A legend is laid out in the border it notches into; with the border gone it still sits on the
 * card's top edge rather than inside it. Floated full width, it behaves as the heading the board
 * draws. */
.adminshell .admin__legend {
    float: left;
    width: 100%;
    margin-bottom: 10px;
    padding: 0;
    font-size: 14px;
    font-weight: var(--font-weight-bold);
}

/* AND THE FLOAT HAS TO BE CLEARED, or the heading above is not a heading.
 *
 * A float 100% wide still leaves a line box beside it, and the next block-level element is laid
 * out INTO that line box rather than below it. On "Users & support" that made the Country field
 * nought pixels wide, with its select painted past the panel's edge and its label clipped — a
 * control a person could see and not use. It was not a small-screen bug: measured at 390 and at
 * 1440, the field was nought pixels at both.
 *
 * Found by measuring the rendered boxes, not by reading the stylesheet, and the campaign screen's
 * two groups are unchanged by this because their first child was already clearing. */
.adminshell .admin__group > *:not(legend) {
    clear: both;
}

.adminshell .admin__note {
    margin-bottom: 16px;
    font-size: 14px;
    line-height: 1.5;
}

/* A field inside a group stands on the group's tint, so it keeps the white ground that tells it
 * apart from it. The colour only: the shorthand also reset the select's chevron image. */
.adminshell .admin__group .field__input,
.adminshell .admin__group .field__select {
    background-color: var(--colour-surface);
}

/* --- The competition draws, measured against AdminCompetitions.dc.html ------------------------ */

/* Every panel on an administration screen is the same shape: a white card with a warm hairline,
 * a 28px radius and 28px of padding. .card is shared with the participant screens, so this is
 * scoped to the admin shell rather than restated on the component. */
.adminshell .card {
    padding: 28px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 28px;
    background: var(--colour-surface);
    box-shadow: none;
}

/* --- The pre-publication panel, from AdminCompetitions.dc.html ------------------------------
 *
 * The board gives this screen one ink panel and puts the state in it: what is not possible yet
 * and the date after which it will be. It was a white card like any other.
 *
 * WRITTEN AT TWO CLASSES, because `.adminshell .card` sets the white — one class could not
 * reach it, and the first attempt drew white text on a white card.
 */
.adminshell .card--ink {
    background: var(--colour-primary);
    border-color: transparent;
}

.adminshell .card--ink .card__eyebrow {
    margin: 0 0 10px;
    color: var(--board-on-ink-label);
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
}

.adminshell .card--ink .card__detail {
    color: var(--colour-text-on-primary);
}

.adminshell .card--ink .card__detail--quiet {
    color: var(--board-on-ink-muted);
}

.adminshell .card--ink .card__date {
    margin: 8px 0 0;
    color: var(--colour-text-on-primary);
    font-size: 24px;
    font-weight: var(--font-weight-bold);
    line-height: 1.2;
}

.adminshell .card__title {
    font-size: 22px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
}

.adminshell .competitions-admin {
    max-width: none;
}

/* --- The two banners, measured against SuperOps.dc.html --------------------------------------- */

.qabar,
.impersonation {
    padding: 14px 20px;
    border-bottom-width: 6px;
    font-size: 15px;
}

.qabar__text,
.qabar__actions,
.impersonation__text {
    font-size: 15px;
}

/* A BORDERED PILL, WHICH IS WHAT THE BOARD DRAWS: the button system's quiet button on ink, 44px
 * with the #C9D6F0 edge (SuperOps.dc.html). It is the one control in a strip that is otherwise a
 * sentence, so it is a target rather than a word. It keeps its own width, not the 12rem floor a
 * button that owns its line takes. */
.impersonation__button {
    width: auto;
    min-width: 0;
    padding: 0 18px;
}

/* --- The support records, measured against SuperRecords.dc.html ------------------------------- */

/* A record's facts are a two-column list of label and value, each row a hairline apart. */
.adminshell .factlist__row {
    padding: 12px 0;
    border-bottom: 1px solid var(--colour-rule-warm-soft);
}

/* THE SEARCH FIELD HAS NO BOX OF ITS OWN: the panel around it is the box. Stated after the
 * administration field figures above, which would otherwise give it their 54px height, their
 * 16px inset and their radius — it is the one field on these screens that is a line rather than
 * a control in a form. The component sheet's 48px floor goes with them; this takes the
 * target-size minimum instead, and the user agent's own inset. */
.adminshell .supportsearch__input {
    flex: 1 1 auto;
    padding: 1px 2px;
    border: 0;
    border-radius: 0;
    background: none;
    font-size: 20px;
}

/* The board's 44px line, at the board's width. On a phone the design contract asks 48 of a
 * target and that wins — this is the one control the screen exists for. */
@media (min-width: 80rem) {
    .adminshell .supportsearch__input {
        height: 44px;
        min-height: var(--touch-target-min);
    }
}

/* ON A PHONE THE FIELD TAKES THE LINE. Held on one row, the field shrank to a sliver beside the
 * privacy sentence at 390 (design review, 2026-09-25); it wraps instead, with the sentence last. */
@media (max-width: 39.99rem) {
    .supportsearch__row {
        flex-wrap: wrap;
    }

    .adminshell .supportsearch__input {
        flex: 1 1 100%;
    }
}

/* THE OPERATOR'S CORNER DOES NOT BREAK. The role is two words and "Sign out" is two words, and
 * on the six-destination Super Admin bar both were wrapping mid-phrase, so both keep their line.
 * The name is never shortened or wrapped: it is drawn from 1440 when it fits one line — see
 * "A NAME IS WHOLE, ON ONE LINE, OR NOT DRAWN" (F-043). */
.adminshell .adminbar__role,
.adminshell .adminbar__out .link-button {
    white-space: nowrap;
}

.adminshell .adminbar__who {
    min-width: 0;
}

.adminshell .adminbar__name {
    flex-shrink: 0;
    white-space: nowrap;
}

/* ==========================================================================================
 * THE PHONE, MEASURED AGAINST MyStepsMobile.dc.html
 *
 * A 390x844 canvas, and the figures on it are its own: eighteen-pixel gutters, a fifty-eight
 * pixel bar, cards with an eighteen-pixel inset (twenty since 2026-10-05, --card-padding-phone) rather than the forty the 1440 board draws, and
 * a day field that is taller and larger than its desktop equivalent because a thumb types into
 * it. The desktop figures had been applied at every width, which left a 342px card with 260px
 * of content inside it — eighty pixels of a phone's width spent on padding.
 * ========================================================================================== */
@media (max-width: 47.9375rem) {
    .appbar__inner,
    .page,
    .shell--wide .page,
    .sitefoot__inner {
        padding-inline: 18px;
    }

    .appbar__inner {
        min-height: 58px;
        padding-block: 0;
    }

    .appbar .gatemark {
        font-size: 14px;
    }

    .whoami__initials {
        width: 32px;
        height: 32px;
        font-size: 12px;
        letter-spacing: normal;
    }

    .pagestack {
        gap: 12px;
    }

    /* --- The cards --- */
    .panel,
.roster-panel,
.board-panel,
.details-panel {
        padding: var(--card-padding-phone);
        border-radius: var(--radius-2xl);
    }

    /* --- The converter, never behind a click --- */
    .converter {
        margin-top: 16px;
        padding: 16px;
        border-radius: 20px;
    }

    /* THE DURATION'S BOX IS ITS WRAPPER, so the wrapper is what takes the phone's 48. This named
     * `.field__input` from before the wrapper carried the edge, and after that it sized only the
     * borderless input inside it: the visible box stayed at the laptop's 56 beside a 48px select,
     * where MyStepsMobile.dc.html draws both at 48 (F-050). */
    .converter .field__withunit,
    .converter .field__select {
        height: 48px;
        padding: 0 14px;
        border-radius: 12px;
        font-size: 15px;
    }

    .converter .field__label {
        font-size: 12px;
    }

    /* --- The standings table ------------------------------------------------------------------
     * Four columns of a leaderboard in 301px. It was eighteen pixels over, so the row tint and
     * the last figure were cut by the scroller rather than reached by it — which reads as a
     * broken card, not as something to swipe. Tighter cells and a smaller column label fit the
     * four columns inside the card, and the scroller stays for the long team name that still
     * does not.
     */
    .board-table th,
    .board-table td {
        padding-inline: 6px;
    }

    /* The rank keeps its inset so the selected row's four-pixel rule does not sit on top of it,
     * and the two figure columns keep a gap wide enough that "100 %" and "55 800" read as two
     * numbers rather than one. The figures come down a step to pay for both. */
    .board-table th:first-child,
    .board-table td:first-child {
        padding-left: 10px;
    }

    .board-table th:nth-child(3),
    .board-table td:nth-child(3) {
        padding-right: 12px;
    }

    .board-table th:last-child,
    .board-table td:last-child {
        padding-right: 0;
    }

    .board-table th {
        font-size: 10px;
    }

    .board-table td {
        font-size: 14px;
    }

    .board-table .num,
    .board-table__figure {
        font-size: 15px;
    }
}

/* ==========================================================================================
 * THE TABLET, MEASURED AGAINST TabletSteps.dc.html
 *
 * A 1024x1560 canvas, and its own note says what it is: the desktop layout at four columns
 * instead of twelve. Thirty-two-pixel gutters, a seventy-three-pixel bar on ONE line, a 44px
 * title, and every card one step tighter than the 1440 board draws it. The implementation was
 * taking the phone's stacked bar here — three rows and 156 pixels of chrome before the page.
 * ========================================================================================== */
@media (min-width: 64rem) and (max-width: 79.9375rem) {
    .appbar__inner,
    .page,
    .shell--wide .page,
    .sitefoot__inner {
        padding-inline: 32px;
    }

    .appbar__inner {
        min-height: 73px;
        padding-block: 0;
    }

    /* One line: the mark, the destinations, and the person at the far edge. */
    .appbar .topbar {
        flex-wrap: nowrap;
        align-items: center;
        gap: 12px;
    }

    .appbar .gatemark {
        flex-shrink: 0;
        font-size: 15px;
    }

    .appbar .bar {
        flex: 1 1 auto;
        flex-wrap: nowrap;
        justify-content: flex-start;
        gap: 1px;
    }

    .appbar .bar__link {
        padding: 9px 12px;
        font-size: 14px;
        white-space: nowrap;
    }

    /* The board shows initials and no name — the name is on the page, and the bar has one line
     * to spend. The name is hidden visually by "A NAME IS WHOLE OR NOT DRAWN" (F-043), not here:
     * it stays in the accessibility tree. Sign out stays: the board's tablet bar leaves it out,
     * and this product has no other way to end a session. */

    .appbar .whoami__initials {
        width: 32px;
        height: 32px;
        font-size: 12px;
    }

    .appbar .whoami,
    .appbar .bar__out {
        flex-shrink: 0;
    }

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

    .panel,
.roster-panel,
.board-panel,
.details-panel {
        padding: var(--card-padding);
        border-radius: var(--radius-2xl);
    }

    .converter {
        padding: 20px 22px;
        border-radius: 22px;
    }
}

/* ==========================================================================================
 * FOUNDATIONS, CHECKED AGAINST Foundations.dc.html
 *
 * The system board is a specification rather than a screen, so what it produced here is one
 * correction and a set of confirmations. Confirmed: the muted text colour is its #4D5E93
 * exactly; panels are white on the warm ground with a hairline; chips are filled and never
 * outlined; a border promises interaction, so the computed total is a tint with no outline and
 * a reported figure has neither; the focus ring is 3px at a 3px offset, white on ink; the
 * navigation order is one per role and the same on every screen; My details holds a name, a
 * language, a time zone and a work e-mail that is shown and explained rather than edited.
 *
 * "No shadows, no gradients": there are no gradients anywhere, and the last drop shadow in the
 * product, on the team's state card, went with that card.
 * ========================================================================================== */
/* ==========================================================================================
 * THE STATE CARD, MEASURED AGAINST StepsStates.dc.html AND CaptainActions.dc.html
 *
 * Between them the two boards draw seven answers Mine skridt can give and five actions a captain
 * can take, and every one of them is the same card: white on the warm ground, a 28px radius,
 * 28px of inset, a 26px heading and body copy under it. A confirmation — "Er 84 000 skridt
 * rigtigt?", "Fjern Lars fra holdet?" — is the same card at 26px with a 20px heading.
 *
 * In this product that card is .gate, worn by the no-campaign screen, the high-value
 * confirmation, the closed roster and the captain's refusal. It was the signed-out gate's own
 * card: a 26rem measure, a 12px radius and a drop shadow the design system does not have.
 *
 * WHAT IS NOT TAKEN FROM THE BOARDS is the small uppercase eyebrow over each heading. It names
 * the state in words the product does not have yet, and writing Danish copy for seven of them is
 * a content decision rather than a measurement. The heading already names the state.
 * ========================================================================================== */
.gate {
    max-width: 34rem;
    padding: 28px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 28px;
    background: var(--colour-surface);
    box-shadow: none;
}

.gate .gate__header {
    margin-bottom: 0;
}

.gate .gate__header h1,
.gate .gate__header h2 {
    margin: 0;
    font-size: 26px;
    line-height: 1.2;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
}

.gate .gate__header .lede {
    margin: 10px 0 0;
    font-size: 16px;
    line-height: 1.55;
    color: var(--colour-text-muted);
}

.gate .gate__note {
    margin: 16px 0 0;
    font-size: 14px;
    line-height: 1.55;
}

/* A confirmation is the same card (its padding is the card's, 24/20 since 2026-10-05), with the
 * question at twenty. */
.gate--confirm .gate__header h1,
.gate--confirm .gate__header h2 {
    font-size: 20px;
}

/* The three sentences Mine skridt says about the campaign's own clock — not begun, entry closed,
 * campaign over — take the component sheet's status shape: a four-pixel rule in the state's
 * colour down the left, the corners rounded away from it, and the words carrying the meaning.
 * They were square-cornered strips with a two-pixel edge. */
.notice {
    margin: 0 0 12px;
    padding: 14px 16px;
    border-left: 4px solid var(--colour-accent-on-surface);
    border-radius: 0 14px 14px 0;
    background: var(--colour-surface-field);
    font-size: 15px;
    line-height: 1.5;
}

/* --- Broadcasts and the rest of the .support screens, against AdminBroadcast.dc.html ----------
 *
 * Every board draws administration work inside a white panel on the warm ground: the broadcast
 * list, the compose form, the audience block, the confirmation. These screens had their forms
 * and their tables standing directly on the ground with nothing around them, which on a page
 * that is otherwise all panels reads as content that failed to load its card.
 */
.adminshell .support > form,
.adminshell .support > .support__scroller,
.adminshell .support > .support__section {
    padding: 28px 32px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 28px;
    background: var(--colour-surface);
}

/* A list is a panel one step tighter than a form, as the broadcast board draws it. */
.adminshell .support > .support__scroller {
    padding: 26px 30px;
}

/* The audience block inside the compose form: the board's tinted panel, not another white card
 * inside a white card. */
.adminshell .support > form .admin__group {
    background: var(--colour-surface-field);
    border: 0;
    border-radius: 20px;
    padding: 20px;
}

/* ==========================================================================================
 * THE BOARD'S OWN STATE GROUNDS
 *
 * Foundations.dc.html draws four states, each a ground, a mark and a word: #E9F4E8 / #3F9C35 /
 * #2A6B22 for saved, joined and running; #FFF6E5 / #EAAB00 / #8A6400 for pending, scheduled and
 * unsaved; #FBE9EF / #E6553F / #B0562F for invalid, missing and failed; #F1EEE9 / #939AA7 /
 * #4D5E93 for closed, locked and not yet. The grounds were Forest Green and Golden Yellow tints
 * computed at fourteen and sixteen per cent; they are the drawn values now.
 *
 * THE WORD IS SET IN THE BOARD'S OWN TEXT COLOUR where that colour clears AA on the ground beside
 * it, which three of the four do: 5.76:1, 5.01:1 and 5.44:1. The fourth, #B0562F on rose, is
 * 4.27:1 — under the threshold a word is held to — so a failure keeps the product's ink and lets
 * the mark carry the colour.
 * ========================================================================================== */
.competition__state--running,
.chip--on {
    color: var(--board-positive-text);
}
/* ==========================================================================================
 * THE PHONE'S TAB BAR, MEASURED AGAINST MyStepsMobile.dc.html
 *
 * 82px tall, white, a hairline along the top, 8px of padding with none at the bottom, and five
 * slots of 70x58 spaced apart. Each slot is a 21px glyph over a 10px label, and the current one
 * is filled with the computed-value tint and set in ink. Below the phone breakpoint it replaces
 * the disclosure in the top bar; above it, it does not exist.
 * ========================================================================================== */
.tabbar {
    display: none;
}

@media (max-width: 47.9375rem) {
    .tabbar {
        position: fixed;
        inset: auto 0 0 0;
        z-index: 90;
        display: flex;
        align-items: flex-start;
        justify-content: space-between;
        min-height: 82px;
        padding: 8px 8px 0;
        background: var(--colour-surface);
        border-top: 1px solid var(--colour-rule-warm);
    }

    /* THE DISCLOSURE IN THE TOP BAR GOES, so there is one navigation at this width and not two.
     * Both remain in the document at every other width for the reason the layout gives; this is
     * the same swap, one breakpoint further down. */
    .appbar .navmenu {
        display: none;
    }

    /* The page ends above the bar rather than behind it. */
    .sitefoot {
        padding-bottom: 82px;
    }

    .tab {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 5px;
        width: 70px;
        height: 58px;
        border-radius: 16px;
        color: var(--colour-text-muted);
        font-size: 10px;
        font-weight: var(--font-weight-semibold);
        text-align: center;
        text-decoration: none;
        white-space: nowrap;
        cursor: pointer;
    }

    .tab__icon {
        display: flex;
    }

    .tab[aria-current='page'],
    .tabmore:has([aria-current='page']) .tab--more {
        background: var(--colour-surface-field);
        color: var(--colour-text);
        font-weight: var(--font-weight-bold);
    }

    /* A disclosure whose panel opens UPWARD, because the bar is at the bottom of the screen.
     * The marker goes: the slot is a glyph and a word like the four beside it. */
    .tabmore {
        position: relative;
    }

    .tabmore > summary {
        list-style: none;
    }

    .tabmore > summary::-webkit-details-marker {
        display: none;
    }

    .tabmore__panel {
        position: absolute;
        right: 0;
        bottom: calc(100% + 10px);
        min-width: 15rem;
        padding: 10px;
        display: flex;
        flex-direction: column;
        gap: 4px;
        background: var(--colour-surface);
        border: 1px solid var(--colour-rule-warm);
        border-radius: 18px;
    }

    .tabmore__link {
        display: flex;
        align-items: center;
        /* Forty-eight on a phone, which is what the design contract asks of a target there and
         * what Foundations.dc.html repeats: "minimum 44px tall, 48px on a phone". */
        min-height: 48px;
        padding: 0 14px;
        border-radius: 12px;
        color: var(--colour-text);
        font-size: 15px;
        font-weight: var(--font-weight-semibold);
        text-decoration: none;
        white-space: nowrap;
    }

    .tabmore__link[aria-current='page'] {
        background: var(--colour-surface-field);
        font-weight: var(--font-weight-bold);
    }
}

/* The grid's confirmation — several high days asked about once — is the same card as the single
 * day's: StepsStates.dc.html draws "To dage ser høje ud" at 26px of inset with a 28px radius and
 * a 20px question, exactly as it draws "Er 84 000 skridt rigtigt?". It was a bare block on the
 * ground with no card around it at all. */
.confirm {
    max-width: 34rem;
    padding: 26px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 28px;
    background: var(--colour-surface);
}

.confirm__heading {
    margin: 0;
    font-size: 20px;
    line-height: 1.2;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
}

.confirm__body {
    margin: 10px 0 0;
    font-size: 16px;
    line-height: 1.55;
    color: var(--colour-text-muted);
}

/* --- Without a team, as StepsStates.dc.html draws it ------------------------------------------
 * A card on the tint, #EDF1FA: a 28px radius, 26px of inset, a small label over a 22px heading,
 * the reason under it, and the action. It was a single quiet line with an inline link, and then
 * a rose card; rose means invalid or failed (ACC-006 decision), and having no team yet is a
 * state to act on, not an error, so the board draws it on the tint.
 */
.noteam {
    padding: 26px;
    border-radius: 28px;
    background: var(--colour-surface-field);
}

.noteam__eyebrow {
    margin: 0;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--colour-text-muted);
}

.noteam__heading {
    margin: 12px 0 0;
    font-size: 22px;
    line-height: 1.2;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
}

.noteam__body {
    margin: 8px 0 0;
    max-width: var(--layout-measure);
    font-size: 15px;
    line-height: 1.5;
    color: var(--colour-text-muted);
}

.noteam__action {
    margin: 14px 0 0;
}

.noteam__button {
    width: auto;
    padding: 0 24px;
}

/* The pending invitations, on the same card: one row per invitation, the sentence and its Accept.
 * Stacked while the CARD is narrow; side by side once there is room for both on one line. A
 * container query, not a viewport one: the same card sits in the wide step screen and in the
 * narrow gate card of "Create your team", which is 340px wide at every viewport. */
.invites {
    container-type: inline-size;
}

.invites__list {
    margin: 14px 0 0;
    padding: 0;
    list-style: none;
}

.invites__row + .invites__row {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--colour-rule-on-tint);
}

.invites__text {
    margin: 0 0 10px;
    color: var(--colour-text);
}

/* Inside the gate card of "Create your team": the card keeps its own distance from the lede, and
 * Accept loses the gate's button margin, so each Accept sits nearer its own sentence than the next
 * invitation's (design review). */
.gatecard .invites {
    margin-top: var(--space-lg);
}

.gatecard .invites .button {
    margin-top: 0;
}

@container (min-width: 480px) {
    .invites__row {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 16px;
    }

    .invites__text {
        margin: 0;
    }
}

/* --- The captain's confirmations, against CaptainActions.dc.html -----------------------------
 *
 * "Fjern Lars fra holdet", "Slet invitationen til Rikke", "Skift til Nordic Striders?" — the
 * board draws each as the same card as every other confirmation in the product: 26px of inset,
 * a 28px radius, and the question at 20px. .decision was a bare column on the ground with a
 * page-title-sized heading, which read as a screen rather than as an ask.
 */
.decision {
    padding: 26px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 28px;
    background: var(--colour-surface);
}

.decision__heading {
    font-size: 20px;
    line-height: 1.2;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
}

.decision__lede {
    margin: 10px 0 0;
    font-size: 16px;
    line-height: 1.55;
    color: var(--colour-text-muted);
}

@media (max-width: 47.9375rem) {
    /* THE PERSON RETURNS TO THE TOP BAR, where MyStepsMobile.dc.html draws them: the mark on the
     * left and a 32px mark of their initials on the right, and nothing else. They were hidden at
     * this width because they lived inside the disclosure the tab bar replaced. */
    .topbar .whoami {
        display: flex;
        /* The rule after the person separates them from the way out, and the way out is in the
         * tab bar's Mere at this width. A divider with nothing on the far side of it is a line
         * to the edge of the screen. */
        padding-right: 0;
        border-right: 0;
    }

    /* The name beside the initials is hidden visually by "A NAME IS WHOLE OR NOT DRAWN" (F-043). */

    .tabmore__person {
        margin: 8px 0 0;
        padding: 10px 14px 0;
        border-top: 1px solid var(--colour-rule-warm);
        font-size: 13px;
        font-weight: var(--font-weight-bold);
        color: var(--colour-text-muted);
    }

    .tabmore__out {
        margin: 0;
        padding: 0 14px 6px;
    }

    .tabmore__out .link-button {
        min-height: 48px;
        font-size: 15px;
        font-weight: var(--font-weight-bold);
    }
}

/* --- Mine oplysninger, the form label the board sets --------------------------------------
 *
 * The board sets a form label at 14px here, as it does on every administration form.
 *
 * HISTORY, AND IT IS WHY THE COLUMN RULE IS NOT HERE. This block was once headed "the two
 * columns the board actually draws" and carried a second `@media (min-width: 80rem)
 * { .profilework }` restating the tracks as `848px 440px`. That was written to stop the tracks
 * sizing themselves to 793 / 495, which they did before the rule up at `.profilework` said
 * `minmax(0, 1fr) 440px`; by the time this one was added the first already produced 848 at the
 * board's measure, so this was a duplicate that hard-coded the answer and lost the ability to
 * shrink. Ten thousand lines from the rule it duplicated, nobody comparing the two would have
 * noticed — which is the whole reason it could be written. It made the page 1440 wide inside a
 * 1265 window and is gone; the reasoning lives beside the surviving rule, where the next person
 * tempted by 848 will actually meet it.
 */
.details-panel .gate__label,
.details-panel .field__label {
    font-size: 14px;
}

/* ==========================================================================================
 * THE LANDING, REBUILT TO Main.dc.html — 1440 x 1700
 *
 * The screenshot comparison that opened this section found the page 730px taller than the board
 * and different in almost every section: the hero was in a white card the board does not draw,
 * the campaign panel was a small card in a column rather than a full-height panel running off
 * the right edge, "Three steps" had no cards and titles that could not be read, the materials
 * teaser was two panels on the warm ground rather than one rose band, and there was a photograph
 * the board has nowhere. None of it was visible to a six-probe property comparison, which had
 * passed this screen at zero differences.
 *
 * What follows is the board's own arithmetic, section by section.
 * ========================================================================================== */

/* --- The bar: 88px, a 96px gutter, two destinations and the language pill --------------------
 * Every rule that was scoped to `.gateshell--landing` here now belongs to `.gatebar--shared`:
 * the height, the missing rule underneath, and the pill. Six guest routes carry that modifier;
 * the onboarding family renders a plain `.gatebar` and keeps its own 64px bordered bar. */
/* THE RIGHT-HAND GROUP, WHICH space-between STOPPED PRODUCING. The boards draw the mark at the
 * left edge and the two destinations and the pill as one group at the right, 28px apart. That
 * used to happen for free: the form was inside the <nav>, so the row had two flex children and
 * `justify-content: space-between` put one at each end.
 *
 * Moving the form out for the accessibility reason above made it three children, and
 * space-between distributes the middle one — so at 1280 the destinations sat at x=527 with 280px
 * of empty ground between "Sign in" and the pill, on all six routes identically. Route-to-route
 * parity cannot see a composition that is wrong the same way everywhere; it took reading the box
 * model and then measuring against the board.
 *
 * `margin-left: auto` on the nav absorbs the free space before it, so the brand stays left and
 * the nav and the form travel right together. At phone width the nav is `flex-basis: 100%` on
 * its own row, where there is no free space for the margin to take, so the rule is harmless
 * there and is left unscoped. */
.gatebar--shared .gatebar__end {
    margin-left: auto;
}

/* Scoped: the onboarding bar renders a `gatebar__end` too, with one child. Inert there today,
 * but the rule is the shared board's and belongs with the rest of them. */
.gatebar--shared .gatebar__end {
    display: flex;
    align-items: center;
    gap: 28px;
}

.gatebar__link {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--colour-text);
    text-decoration: none;
    white-space: nowrap;
}

.gatebar__link:hover {
    text-decoration: underline;
}

/* THE LANGUAGE SWITCH AS THE BOARD'S PILL: a white trough with a hairline, the current language
 * filled with ink and the other quiet, both reading as two-letter codes. The word "Language" and
 * the endonyms stay in the markup for everything else that renders this partial — and for a
 * screen reader here, where the two-letter code is aria-hidden and the endonym is the name.
 *
 * SCOPED TO THE SHARED BAR, NOT TO THE LANDING PAGE. The same partial renders in the profile
 * card, in the application footer and in the onboarding bar, all of which must keep the
 * endonyms; `.gatebar--shared` is what distinguishes the six routes that draw the pill. */
.gatebar--shared .language {
    margin: 0;
}

.gatebar--shared .language__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.gatebar--shared .language__options {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 4px;
    background: var(--colour-surface);
    /* --board-rule, NOT --board-rule-landing. All three guest boards draw this trough at
     * #E9E4DC; the landing tint is #E4DFD8, and tokens.css's own rationale names exactly this
     * case — two hairlines from different drawings meeting on one screen. On /materials the
     * .mat cards beside it already use #E9E4DC. */
    border: 1px solid var(--board-rule);
    border-radius: var(--radius-pill);
}

.gatebar--shared .language__current,
.gatebar--shared .language__choice {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 8px 16px;
    border: 0;
    border-radius: var(--radius-pill);
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-decoration: none;
}

.gatebar--shared .language__current {
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
}

.gatebar--shared .language__choice {
    background: transparent;
    color: var(--colour-text-muted);
    cursor: pointer;
}

/* The endonym is the accessible name everywhere; the code is what this bar shows. */
.language__code {
    display: none;
}

.gatebar--shared .language__endonym {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.gatebar--shared .language__code {
    display: inline;
}

/* --- The hero: 780px, no card, the panel running off the right edge -------------------------- */
@media (min-width: 80rem) {
    .gateshell--landing .gatemain--split .gatemain__inner {
        display: grid;
        /* 928, NOT 760. The board's left column states width: 760px and then adds 96 and 72 of
         * padding to it — its own box is content-box, so the column measures 928 and the panel
         * begins there. Read off the rendered board rather than off its declaration.
         *
         * 928 AT MOST, AND NEITHER COLUMN NARROWER THAN ITS OWN CONTENT (F-052). The panel's
         * widest line is the step total — 68px, never wrapped — or before the first day the
         * dates row: "154 965" needs 289px, and at 1280 a fixed 928 left the panel 177 inside its
         * 64 and 96 of padding, so the number ran 16px past the viewport. Both tracks are floored
         * at their min-content, and the hero gives up what the panel needs. With a six-digit total
         * nothing moves from about 1400, and 1440 is the board's 928; below that the headline
         * takes the two lines Main.dc.html draws it on, inside the same 780. The board's own
         * "121 748 302" fits at every width from 80rem with the hero at 662-822. Only a
         * ten-digit total, which no campaign reaches, would make the page scroll, and it scrolls
         * rather than sliding the headline under the panel. */
        grid-template-columns: minmax(auto, 928px) minmax(auto, 1fr);
        align-items: stretch;
        gap: 0;
        min-height: 780px;
        max-width: none;
        padding-inline: 0;
    }

    /* THE HERO IS NOT A CARD. It was the gate's white panel; the board stands it on the ground. */
    .gatecard--landing {
        display: flex;
        flex-direction: column;
        justify-content: center;
        max-width: none;
        margin: 0;
        padding: 0 72px 0 96px;
        border: 0;
        border-radius: 0;
        background: none;
        box-shadow: none;
    }
}

.gatecard--landing .gatecard__head {
    margin-bottom: 0;
}

.gatecard--landing .gatecard__lede {
    max-width: 470px;
    line-height: 1.55;
    color: var(--colour-text-muted);
}

.gatecard--landing .gate__form {
    margin-top: 40px;
    max-width: 520px;
}

.gatecard--landing .gate__label {
    display: block;
    margin-bottom: 10px;
    font-size: 14px;
    font-weight: var(--font-weight-bold);
}

/* The field and the action on one row: a 56px box that grows and a 56px primary that does not
 * (Main.dc.html; the row was 64 before the button system). */
.gate__entry {
    display: flex;
    /* The item-12 field (48) beside the 56px button, centred on one line; stacked rows stretch. */
    align-items: center;
    gap: 12px;
}

/* In the row the field's and the button's own top margins (the gate form spaces each under the
 * one before) would push them off each other's centre. */
.gate__form .gate__entry .field__input,
.gate__form .gate__entry .gate__entry-submit {
    margin-top: 0;
}

.gatecard--landing .gate__entry .field__input {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
    max-width: none;
    min-height: 0;
    background: var(--colour-surface);
}

/* .gate__entry-submit, NOT .gate__submit: that class already exists on the admin identity form,
 * and a landing-only width would have followed it there.
 *
 * Written at .gatecard--landing's specificity because .gatecard .button sets width: 100%, which
 * as a flex-basis takes the whole row and leaves the field a 46px sliver. flex rather than width
 * alone, for the same reason. */
.gatecard--landing .gate__entry-submit {
    flex: 0 0 auto;
    width: auto;
    min-width: 0;
    gap: 10px;
    padding: 0 32px;
    letter-spacing: normal;
}

.gatecard--landing .gate__hint {
    margin: 14px 0 0;
    font-size: 15px;
    color: var(--colour-text-muted);
}

.gatecard--landing .gatecard__return {
    margin: 8px 0 0;
    font-size: 15px;
    color: var(--colour-text-muted);
}

/* The three facts as one row above a rule, divided by hairlines. */
.gatecard--landing .gatecard__steps {
    margin: 44px 0 0;
    padding: 24px 0 0;
    border-top: 1px solid var(--board-rule-landing);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 28px;
    list-style: none;
}

.gatecard--landing .gatecard__steps li {
    position: relative;
    margin: 0;
    padding: 0;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--colour-text);
}

.gatecard--landing .gatecard__steps li::marker {
    content: '';
}

/* THE RULE TRAILS AN ITEM RATHER THAN LEADING THE NEXT ONE.

 * Drawn on the left of every item after the first, a wrapped row puts a hairline at the start of
 * a new line with nothing on its other side — which is what "Sign-ups close Sunday 20 September"
 * did the moment it joined the row. Drawn on the right of every item but the last, the same row
 * wraps with the rule at the end of the line it belongs to, which is where a separator reads as
 * a separator. Same trap the competition facts and the tablet hero fell into. */
/* The middot the gate cards use is not drawn here: this row has its own hairline, and two
 * separators between the same pair of facts is one too many. */
.gatecard--landing .gatecard__steps li + li::before {
    content: none;
}

.gatecard--landing .gatecard__steps li:not(:last-child)::after {
    content: '';
    position: absolute;
    right: -14px;
    top: 50%;
    width: 1px;
    height: 18px;
    transform: translateY(-50%);
    background: var(--board-rule-landing);
}

.gatecard--landing .gatecard__note {
    display: none;
}

/* THE HERO ROW IS 780 AND NOTHING ELSE. The gate shell gives its main 64px above and below, for
 * the eight screens that are one card floating on the ground; the landing's hero is a full-bleed
 * band whose own height the board states, and the padding was adding 128px to the page before a
 * single section had been measured. */
@media (min-width: 80rem) {
    .gateshell--landing .gatemain {
        padding-block: 0;
    }
}

/* --- The hero's vertical rhythm, line for line ------------------------------------------------
 *
 * The board's column is: eyebrow, 20 to an 82px headline, 24 to the lede, 40 to the form, then
 * inside the form a 14px label 10 above a 64px row, 14 to the first sentence and 8 to the second,
 * then 44 and a rule to the fact row. Measured against it, this column carried 96px the board
 * does not have — .field's own 32 above and 24 below, a 24px margin on the label, and 16px of
 * something inside the entry row — and set its two helper lines at a line-height half again as
 * loose as drawn. Ninety-six pixels of nothing, in the one column the page exists for.
 */
.gatecard--landing .field {
    margin: 0;
}

.gatecard--landing .gate__label {
    margin-top: 0;
    font-size: 14px;
    line-height: 1.15;
}

.gatecard--landing .gate__entry > * {
    margin: 0;
}

.gatecard--landing .gate__hint,
.gatecard--landing .gatecard__return {
    line-height: 1.2;
}

/* --- The landing below the board's own width -------------------------------------------------
 *
 * Main.dc.html is a 1440 canvas and its hero is a 928px column beside a panel; none of that
 * survives a 390px screen. The figures above are scoped to 80rem where they are not obviously
 * fluid, and these are the ones that needed saying again: a 520px form on a 390px phone pushed
 * the whole card 73px off the left edge of the viewport.
 */
@media (max-width: 79.9375rem) {
    .gatecard--landing .gate__form {
        max-width: none;
    }

    .gate__entry {
        flex-direction: column;
        align-items: stretch;
    }

    .gatecard--landing .gate__entry-submit {
        width: 100%;
        justify-content: center;
    }
}

/* --- Two targets the board draws smaller than this product allows ---------------------------
 *
 * The bar's one link is a 24px line of text and its language pill is 32px tall as drawn, both
 * under the 44px the design contract sets for a target and Foundations.dc.html repeats. The
 * painted pill keeps the board's padding; what grows is the box around the words, which is the
 * part a thumb has to hit.
 */
.gatebar__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
}

.gatebar--shared .language__current,
.gatebar--shared .language__choice {
    min-height: var(--touch-target-min);
}

@media (max-width: 47.9375rem) {
    /* Forty-eight on a phone, which is what Foundations.dc.html asks of a target there — the
     * board, not the Novo design contract, which sets no target size at all. */
    .gatebar__brand,
    .gatebar__link,
    .gatebar--shared .language__current,
    .gatebar--shared .language__choice {
        min-height: 48px;
    }
}

/* --- The two summary cards, from Standings.dc.html at 1440x1180 ------------------------------
 *
 * A pair of cards above the board: the reader's own place on ink, their team's on white. The
 * board gives each one a 52px place on the left and a 34px second figure on the right, so the
 * question the screen exists to answer is legible from across a desk and the supporting figure
 * is clearly the supporting one.
 *
 * DESCRIPTION LISTS DRAWN AS CARDS. The markup is dt/dd pairs — see the partial for why — so
 * every rule here is about arrangement and nothing about it carries meaning of its own.
 */
.summarycards {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 20px;
}

.summarycard {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    margin: 0;
    padding: 28px 32px;
    border-radius: 28px;
}

.summarycard--you {
    background: var(--colour-primary);
}

.summarycard--team {
    background: var(--colour-surface-raised);
    border: var(--border-width) solid var(--colour-rule-warm);
}

/* The right-hand pair is the quieter of the two and is set against the card's outer edge, which
 * is what puts the whole card's weight on the place rather than on the total beside it. */
.summarycard__pair--aside {
    text-align: right;
}

.summarycard__eyebrow {
    margin: 0;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
}

.summarycard__value {
    margin: 12px 0 0;
    display: flex;
    flex-direction: column;
}

.summarycard__figure {
    font-size: 52px;
    line-height: 1;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.035em;
}

/* WHERE THERE IS NO PLACE, WORDS TAKE THE NUMERAL'S SLOT. "Not in the standings yet" set at 52px
 * would be a headline about a non-event; it is set at the size of a strong sentence instead, and
 * the card keeps its height from the pair beside it. */
.summarycard__figure--words {
    font-size: 22px;
    line-height: var(--line-height-tight);
    letter-spacing: -0.01em;
}

.summarycard__figure--second {
    font-size: 34px;
    letter-spacing: -0.02em;
}

.summarycard__sub {
    margin-top: 10px;
    font-size: 15px;
    line-height: var(--line-height-base);
}

.summarycard__sub--second {
    margin-top: 6px;
    font-size: 13px;
}

/* The two voices on ink: the accent for the labels, the stepped-down white for the notes, and
 * white itself for the figures. Both are recorded against True Blue in tokens.css. */
.summarycard--you .summarycard__eyebrow {
    color: var(--colour-accent-on-primary);
}

.summarycard--you .summarycard__figure {
    color: var(--colour-text-inverse);
}

.summarycard--you .summarycard__sub {
    color: var(--colour-text-on-primary-muted);
}

.summarycard--team .summarycard__eyebrow,
.summarycard--team .summarycard__sub {
    color: var(--colour-text-muted);
}

.summarycard--team .summarycard__figure {
    color: var(--colour-text);
}

/* ONE CARD PER ROW ON A PHONE, and the pairs stack inside it: two 52px figures side by side at
 * 390px leaves neither of them room, and the right-hand one would be ranged against an edge the
 * eye no longer reads as an edge. */
@media (max-width: 47.9375rem) {
    .summarycards {
        grid-template-columns: minmax(0, 1fr);
        gap: 12px;
    }

    .summarycard {
        flex-direction: column;
        align-items: flex-start;
        gap: 18px;
        padding: 22px 24px;
        border-radius: 24px;
    }

    .summarycard__pair--aside {
        text-align: left;
    }

    .summarycard__figure {
        font-size: 40px;
    }

    .summarycard__figure--second {
        font-size: 28px;
    }
}

/* --- The scope row's own word, from Standings.dc.html ---------------------------------------- */
.filters__prefix {
    margin-right: 4px;
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--colour-text-muted);
    white-space: nowrap;
}

/* --- The board's own column widths, from Standings.dc.html -----------------------------------
 *
 * The board draws `78px minmax(0, 1fr) 150px 160px 160px` with a 20px gutter between every pair.
 * A table has no gutter, so the widths here carry it: the three figure columns are the drawn
 * width plus the gutter that would have sat to their left, which lands each column's right edge
 * exactly where the board puts it — 980, 1160 and 1340 at this canvas.
 *
 * WITHOUT THIS THE TABLE DISTRIBUTES WHAT EACH COLUMN HAPPENS TO CONTAIN. A roster of short names
 * gave the name column eighty pixels it had no use for and pushed every figure right of where it
 * is drawn; a roster of long ones would have done the opposite, so the board's proportions moved
 * with its data.
 *
 * THE TWO BOARDS SHARE THE SHAPE. Personal is rank, name, entered, steps, average; teams is rank,
 * team, members, entered, average. Five columns either way, one figure column narrower than the
 * two beside it, so one set of widths is right for both.
 *
 * LAPTOP AND WIDER ONLY. Below that the table drops columns into the name cell and scrolls, and a
 * fixed layout would be fighting a design that is deliberately not this one.
 */
@media (min-width: 64rem) {
    /* SCOPED TO THE STANDINGS PANEL, and that scope is load-bearing. `.board-table` is the
     * product's one table shape and is worn by the broadcasts list as well; a fixed layout with
     * a 78px first column is right for a rank and turned a message title into an overlap. A
     * measurement taken from one board applies to that board. */
    .board-panel .board-table {
        table-layout: fixed;
    }

    .board-panel .board-table thead th:nth-child(1) {
        width: 78px;
    }

    .board-panel .board-table thead th:nth-child(3) {
        width: 170px;
    }

    .board-panel .board-table thead th:nth-child(4),
    .board-panel .board-table thead th:nth-child(5) {
        width: 180px;
    }
}

/* --- Mine oplysninger's right-hand column, from MyDetails.dc.html at 1440x1060 ---------------
 *
 * Three cards: the address, the team, and everything held about them.
 */

/* THE ADDRESS CARD'S ONE LINE ON CHANGING IT, a caption under the address as the board sets it
 * (14px, muted, 6px below), with support's link inside the sentence. */
.emailcard__onward {
    margin: 6px 0 0;
    font-size: 14px;
    line-height: 1.55;
    color: var(--colour-text-muted);
}

/* EVERYTHING HELD ABOUT THIS PERSON, AS A LIST, because that is what it is — four separate
 * things rather than a sentence with commas in it. The generous line height is the board's, and
 * it is doing work: a reader checking a list against their own expectations reads it item by
 * item rather than as prose. */
.storedcard__list {
    margin: 12px 0 0;
    padding-left: 20px;
    font-size: 16px;
    line-height: 1.8;
    color: var(--colour-text);
}

.storedcard__note {
    margin: 12px 0 0;
    font-size: 14px;
    line-height: 1.55;
    color: var(--colour-text-muted);
}

/* --- The language switch inside the details card, from MyDetails.dc.html --------------------
 *
 * The board puts it under the time zone and above Save, as the third of the three answers the
 * reader decides, and it is saved with the other two (see partials/details).
 */
.profileform__language {
    margin-top: 22px;
    /* It is a fieldset now; its divider comes from the card's rule, not the browser's groove. */
    padding: 0;
    border: 0;
}

.profileform__language-label {
    margin: 0;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    color: var(--colour-text);
}

/* --- Mine oplysninger's own measurements, from MyDetails.dc.html ---------------------------- */

/* 20px between the cards, which is the board's gutter and the same one the summary cards on
 * Stilling use. --space-md is 24 and belongs between sections rather than inside a column. */
@media (min-width: 80rem) {
    .profilework__aside {
        gap: 20px;
    }
}

/* --- The saved band on Mine oplysninger, from MyDetails.dc.html ------------------------------
 *
 * The shape: the check beside the sentence, a touch more air than the neutral band. Its ground,
 * ink and edge are the flat v4 band — see "THE SAVED BAND, FLAT" near the end of the sheet. The
 * check repeats the meaning in shape, so nothing depends on telling the colour (WCAG 2.2 AA 1.4.1).
 */
.status--success {
    display: flex;
    align-items: center;
    gap: 12px;
    /* The board's own 14 by 18 and 16px round, a touch wider and softer than the neutral band —
     * it is the only one carrying a mark beside its sentence. */
    padding: 14px 18px;
}

.status--success .status__title {
    font-size: 16px;
    color: inherit;
}

.status__mark {
    flex-shrink: 0;
}

/* THE RED EDGE WINS OVER THE INK ONE. The first field in this card carries a 2px ink border —
 * the board marks the one the reader starts in — and that rule is written after the invalid
 * state's, so a field that had just been rejected went on drawing the resting mark. Stated here,
 * last, because a wrong answer outranks a starting point. */
.details-panel .field .field__input[aria-invalid='true'],
.details-panel .field .field__select[aria-invalid='true'] {
    border: 2px solid var(--colour-danger);
}

/* A 22px address in a 440px column is the board's. In a 358px one it breaks mid-word, because
 * an address has nowhere else to break — so the phone gets it at reading size instead. */
@media (max-width: 47.9375rem) {
    .emailcard__value {
        font-size: 18px;
    }
}

/* --- Mit hold's own measurements, from MyTeam.dc.html at 1440x1340 --------------------------- */

/* THE DEADLINE CARD SAYS THE DAY ONCE. The moment underneath is its own line now — the board
 * sets the weekday and date at 28 and the time with its zone at 20 — so the rule that promoted
 * the first note to that role has nothing left to promote and would bold the closing sentence. */
.deadline-panel__date {
    font-size: 28px;
}

.deadline-panel__time {
    margin: 6px 0 0;
    color: var(--colour-text-on-primary);
    font-size: 20px;
    font-weight: var(--font-weight-bold);
}

.deadline-panel__note:first-of-type {
    margin-top: 12px;
    color: var(--board-on-ink-muted);
    font-size: 15px;
    font-weight: var(--font-weight-regular);
}

/* --- The invitations table, from MyTeam.dc.html's `.irow` ------------------------------------
 *
 * THE BOARD'S GRID IS DRAWN AT THE BOARD'S WIDTH, AND ONLY THERE. `MyTeam.dc.html` is a 1440
 * artboard and its `.irow` is `minmax(0, 1fr) 170px 120px 280px`. Those three numbers total 570,
 * which the table can afford at 1440 — it is 779 wide there, so the address keeps 209.
 *
 * AND IT COULD NOT AFFORD THEM AT 1280, WHICH IS WHERE THIS BROKE (F-038). The rows stack below
 * 80rem, so the desktop table's narrowest live width is 1280 — where the left column gives it
 * 619. Three pinned columns took 566 of that and the address was left with **53 pixels**, so
 * `thomas.berg@novonordisk.com` wrapped to SIXTEEN lines, 430px tall, one or two characters at a
 * time. Driven, not inferred. The comment that used to stand here said "the address is the
 * column that gives", which was exactly the defect written down as if it were a design: it gave
 * everything, because `overflow-wrap: anywhere` will break a word at any width and a fixed
 * layout never asked whether there was room.
 *
 * SO THE PINNED GRID APPLIES FROM THE BOARD'S OWN WIDTH UP, and between stacking and that width
 * the table is allowed to distribute: the address keeps a floor wide enough to hold an address,
 * and the three beside it shrink to their content — including the two actions, which wrap onto
 * two lines rather than squeezing the only column that carries a person's identity.
 */
/*
 * 88rem, NOT 90rem, AND THE FIFTEEN PIXELS ARE THE POINT. A media query is answered by the
 * viewport WITHOUT its classic scrollbar, so a maximised 1440 window on a machine that draws one
 * asks at 1425 and fell through this rule into the fallback band — at exactly the width the
 * board is drawn at and the width acceptance measures. 88rem is 1408px: wide enough to catch a
 * 1440 window whatever its scrollbar does, and still above 1400, which genuinely is below the
 * board.
 */
@media (min-width: 88rem) {
    .roster-table--invites {
        table-layout: fixed;
    }

    .roster-table--invites thead th:nth-child(2) {
        width: 170px;
    }

    .roster-table--invites thead th:nth-child(3) {
        width: 120px;
    }

    /*
     * 296, WHICH IS THE BOARD'S 280 PLUS THIS CELL'S OWN INSET. The board's `.irow` column is a
     * CONTENT width — its 20px gutters sit outside it — whereas a table cell's width includes
     * its padding, and this one keeps a 16px left inset while the override below zeroes only the
     * right. Stated as 280 the content box was 264, the two pills need 279 at the board's 8px
     * gap, and they wrapped: at 1440 the row drew 138px tall where the board draws one 44px
     * line, and it did the same at every desktop width above it. 296 makes the content box
     * exactly the board's 280. Driven at seven widths, not calculated.
     */
    .roster-table--invites thead th:nth-child(4) {
        width: 296px;
    }
}

/*
 * THE MEMBER ACTIONS STACK BELOW THE WIDTH WHERE THEY NO LONGER FIT (F-041).
 *
 * `.roster-table__action-cell` is `width: 1%` with `white-space: nowrap`, which is the table
 * idiom for "as wide as your content needs" — and with two 44px pills side by side that content
 * is 297px which cannot give. Between 80rem and here the panel is narrower than the columns add
 * up to, so the table overflowed it: measured, 74px over at 1280 and 54px at 1300. The
 * invitations table beside it was given exactly this under F-038 and fits; only the member rows
 * were left rigid, which is why the earlier sweep — which measured the invitations — reported
 * the screen clean.
 *
 * THE SEAM IS SHARED WITH THE INVITATIONS TABLE, and that is why this ends at 88rem rather than
 * at the width where these two pills stop fitting. Measured, they fit from a 1354px viewport up
 * — driven, fine at 1355 and 4px over at 1350 — so 85rem would have been the honest bound for
 * this table alone. It made the panel disagree with itself: the invitations pair stacks to
 * 87.999rem under F-038, so between 1360 and 1407 a captain read two lists of the same four pill
 * controls, one pair stacked and one side by side, with no difference in meaning behind the
 * difference in shape. Driven at 1400, 1366 and 1360 before this was written.
 *
 * So both tables stack from 80rem and both return to the board's side-by-side at 88rem, which is
 * already the width where the invitations grid takes the board's own column numbers. The cost is
 * that the member pair stacks between 1360 and 1407 where it would have fitted; the gain is that
 * the two families are never laid out two ways at once, which is the rule the narrow-width block
 * further up this file records having already been fixed once.
 *
 * WHY NOT LET THEM WRAP INSTEAD, which needs no number at all: `width: 1%` means "give this
 * column its MINIMUM", and once a wrapped pair's minimum is one button the column collapses and
 * the actions stack at 1440 too, where the board draws them side by side. Unsetting the width
 * did not help either — auto layout hands the column a share rather than what it asks for, and
 * the pair still wrapped with 72px spare in the panel. Both were driven before this was written.
 */
@media (min-width: 80rem) and (max-width: 87.999rem) {
    .roster-table:not(.roster-table--invites) .roster-table__actions {
        flex-direction: column;
        align-items: flex-end;
    }
}

/*
 * BETWEEN STACKING AND THE BOARD'S WIDTH, the table decides for itself. `table-layout: auto` is
 * the default and is restated here so the intent is legible beside the rule above it.
 */
@media (min-width: 80rem) and (max-width: 87.999rem) {
    .roster-table--invites {
        table-layout: auto;
    }

    /*
     * THE FLOOR IS WHAT STOPS THE WRAP, and 10rem is what the bottom of the band can afford.
     * This was 11rem (176px), and at the band's own lower edge — a 1280 window, the ordinary
     * desktop `docs/deployment.md` names — the four columns then asked for 631px inside a 619px
     * panel and the table overflowed it. The three beside the address are content-sized and
     * cannot give: a chip reading "Invitation sent" and a date reading "17 September" are as
     * narrow as they are. So the claim comes down by one rem, which still holds
     * `thomas.berg@novonordisk.com` on two lines rather than sixteen, and the table fits its
     * panel across the whole band. Swept at every width from 1280 to 1440.
     */
    .roster-table--invites .roster-table__address {
        min-width: 10rem;
    }

    /* Content-sized, and allowed to be narrower than the board draws them, because at this width
     * the board's numbers do not fit and the address is the column that must not lose. */
    .roster-table--invites thead th:nth-child(2),
    .roster-table--invites thead th:nth-child(3) {
        width: 1%;
        white-space: nowrap;
    }

    /* The two actions stack rather than forcing the row wider, which is the give the advisor's
     * F-038 note names: "HANDLING's two quiet buttons may stack". */
    .roster-table--invites .roster-table__actions {
        flex-direction: column;
        align-items: flex-end;
        gap: 8px;
    }
}

@media (min-width: 80rem) {
    /*
     * `anywhere`, AND THE FLOOR ABOVE IS WHAT MAKES IT SAFE. This read `break-word`, on the
     * reasoning that `anywhere` is what once turned a too-narrow column into one character per
     * line. The two differ in the thing that matters here: `anywhere` reduces the element's
     * MIN-CONTENT size and `break-word` does not (CSS Text 3), and an email address offers no
     * line-break opportunity at `@` or at a dot between letters (UAX #14). So the column's
     * minimum stayed the whole address as one unbreakable word, `width: 100%` could not shrink
     * it, and at 1280 — the ordinary desktop `docs/deployment.md` names — the invitations table
     * overflowed its panel: content 748 against a 619px box, measured, with the 28-character
     * address already in the fixture.
     *
     * `anywhere` collapses that minimum so nothing can overflow; the 10rem floor in the band
     * above is what stops it collapsing all the way to one character per line. The floor is the
     * guard, not the break mode — which is what the old comment had the wrong way round.
     *
     * THE FLOOR ONLY GUARDS THE BAND. This declaration reaches every width from 80rem up, and
     * above 88rem there is no floor at all: `table-layout: fixed` and the stated column widths
     * are what bound the address there, so `anywhere` has nothing to collapse past.
     */
    .roster-table--invites .roster-table__address {
        overflow-wrap: anywhere;
    }

    /* The cell keeps `width: 1%` for the members table, which wants it; here the width is stated
     * and the actions range right inside it, as the board draws them. */
    .roster-table--invites .roster-table__action-cell {
        width: auto;
        /* Flush with the panel's inner edge, as the board's last column is. */
        padding-right: 0;
        white-space: normal;
    }

    /* THE BOARD'S GAP IS 8, on both the member rows and the invitation rows, and the member
     * family already uses it (`--space-2xs`). This said 16, which is what made 178 + 93 need
     * 287px in a 268px box. One control, one rule — including the space between a pair. */
    .roster-table--invites .roster-table__actions {
        flex-wrap: wrap;
        gap: var(--space-2xs);
        justify-content: flex-end;
    }

    .roster-table--invites .roster-table__when {
        white-space: nowrap;
    }
}

/* --- Changing where the team counts, behind the board's two rows ----------------------------- */
.place-change {
    margin-top: 16px;
}

.place-change__summary {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
    color: var(--colour-accent-on-surface);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    cursor: pointer;
}

.place-change__summary:hover,
.place-change__summary:focus-visible {
    color: var(--colour-text);
}

/* Open, the form needs the air a panel's contents get; closed, the summary is the whole card's
 * last line and the rule above it would be a rule under nothing. */
.place-change[open] .placeform {
    margin-top: 8px;
    padding-top: 16px;
    border-top: var(--border-width) solid var(--colour-rule-warm-soft);
}

/* The rotate control and its consequence are one line, not two: the least room that still says
 * what pressing it does. It was the product's own addition, for a captain whose shared link has
 * travelled too far, and the board drew neither part of it — until ACC-005 item 4, which added
 * the line to `MyTeam.dc.html` rather than carrying it as a permanent exception. */
.invite__rotate {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px;
}

/* --- The front door's own measurements, from AdminOverview.dc.html at 1440x1120 -------------- */

/* A PANEL HEAD WITH A NOTE ON THE RIGHT OF IT. Two of the three panels here are titled that way:
 * the heading says what the panel is and the line opposite says what kind of thing is in it —
 * counts rather than warnings, a short list rather than a page that failed to load. */
.adcard__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px 24px;
}

.adcard__aside {
    margin: 0;
    font-size: 15px;
    color: var(--colour-text-muted);
}

/* A FIGURE LONGER THAN SEVEN CHARACTERS STEPS DOWN. Four equal columns of a 900px panel give a
 * figure about 190px, which 44px carries to seven glyphs and no further. A campaign's first day
 * produces a six-figure step total and its last a ten-figure one, so this is the ordinary case
 * rather than an edge: the alternative is a number painted over the column beside it. */
.statcard__value--long {
    font-size: 34px;
    letter-spacing: -0.03em;
}

/* --- Needs attention, as AdminOverview.dc.html draws a row ----------------------------------
 *
 * What is wrong, what follows from it, and the action against the right edge.
 * The rows were a figure and a sentence, which reads as a report; this reads as a list of
 * things to do, which is what the panel is for.
 */
.attention__row {
    display: flex;
    align-items: center;
}

.attention__stack {
    flex-grow: 1;
    min-width: 0;
}

.attention__arrow {
    flex-shrink: 0;
}

.attention__action {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    text-decoration: none;
}

.attention__action:hover,
.attention__action:focus-visible {
    text-decoration: underline;
}

/* On a phone the action drops under the words rather than squeezing them into a column two
 * syllables wide. */
@media (max-width: 47.9375rem) {
    .attention__row {
        flex-wrap: wrap;
        gap: 12px 18px;
    }
}

/* --- The e-mail centre as one screen, from AdminEmail.dc.html at 1440x1220 -------------------
 *
 * Three columns: the messages, the one being written, and what it will look like on arrival.
 * The board gives the list about a fifth of the width and splits the rest between the other
 * two, which is what makes the list scannable without ever competing with the form.
 */
@media (min-width: 64rem) {
    .editor {
        grid-template-columns: 340px minmax(0, 1.4fr) minmax(0, 1fr);
        gap: 20px;
    }
}

@media (min-width: 80rem) {
    .editor {
        grid-template-columns: 355px minmax(0, 1.25fr) minmax(0, 1fr);
    }
}

.maillist {
    padding: 28px 30px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: 28px;
    background: var(--colour-surface);
}

.maillist__label {
    margin: 0;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--colour-text-muted);
}

.maillist__items {
    margin: 14px 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* A ROW IS A LINK AND IS SHAPED LIKE ONE: the whole block is the target, so a name and its
 * state are pressed together rather than the name alone being the only thing that works. */
.maillist__item {
    display: block;
    padding: 14px 16px;
    border-radius: 16px;
    color: var(--colour-text);
    text-decoration: none;
}

.maillist__item:hover {
    background: var(--colour-surface-warm);
}

.maillist__item--on {
    background: var(--colour-surface-field);
}

.maillist__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}

.maillist__name {
    font-size: 17px;
    font-weight: var(--font-weight-bold);
}

/* THE STATE IS A WORD, NOT A COLOUR. Both are chips (advisor Q4, the F-022 family rule): "Default"
 * the quiet one — a hairline and the muted word — and "Edited", the one worth noticing, filled.
 * Neither depends on telling one tint from another (WCAG 2.2 AA 1.4.1). The rule is the family's,
 * so the Materials list's states (Default, Read only, a missing language) wear the same chips. */
/* The board's small chip, `4px 10px` at 12px, measured outside the hairline: the 1px border is
 * taken out of the padding so the quiet chip and the filled one are the same size. */
.maillist__state {
    flex-shrink: 0;
    padding: 3px 9px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: var(--radius-pill);
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    color: var(--colour-text-muted);
}

.maillist__state--edited {
    border-color: var(--colour-surface-field);
    background: var(--colour-surface-field);
    color: var(--colour-text);
}

/* The selected row is itself the field tint, so there the filled chip is white. On every other
 * row — white, like the panel — the tint is what makes it the filled one (design review). */
.maillist__item--on .maillist__state--edited {
    border-color: var(--colour-surface-raised);
    background: var(--colour-surface-raised);
}

/* Only the selected row explains itself, which is what keeps six rows a list rather than six
 * paragraphs. */
.maillist__about {
    display: block;
    margin-top: 6px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--colour-text-muted);
}

/* --- The editor's own head ------------------------------------------------------------------ */
.editor__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px 20px;
}

.editor__title {
    margin: 0;
    font-size: 24px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
}

/* --- The placeholders, as a block rather than a line ----------------------------------------
 *
 * The board gives them a tinted block of their own under the fields, which is the difference
 * between a note somebody reads and a note somebody scrolls past. Without it an operator has no
 * way to learn that :name exists, and a message greeting twenty thousand colleagues with a
 * literal ":name" is the failure that follows.
 */
.placeholders {
    margin: 0 0 var(--space-xs);
    padding: 16px 18px;
    border-radius: 16px;
    background: var(--colour-surface-field);
}

.placeholders__label {
    margin: 0;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--colour-text-muted);
}

.placeholders__list {
    margin: 8px 0 0;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
}

.placeholders__one {
    font-family: inherit;
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    color: var(--colour-text);
}

/* --- The preview's head --------------------------------------------------------------------- */
.editor__preview-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px 16px;
}

.editor__preview-locale {
    margin: 0;
    font-size: 14px;
    font-weight: var(--font-weight-bold);
    color: var(--colour-text-muted);
}

/* --- Broadcasts, from AdminBroadcast.dc.html at 1440x1240 -----------------------------------
 *
 * The list of campaign mails, and under it the one being written with everything about SENDING
 * it in a column of its own.
 */
.broadcasts__empty {
    margin: 20px 0 0;
    font-size: 15px;
    line-height: 1.55;
    color: var(--colour-text-muted);
}

.broadcasts__table {
    margin-top: 6px;
}

/* The board's own columns: the subject takes the room, the three facts about it take what they
 * need. Without this the title column and the state column share whatever the browser decides,
 * and a long subject squeezes the state into a word per line. */
@media (min-width: 64rem) {
    .broadcasts__table thead th:nth-child(2) {
        width: 180px;
    }

    .broadcasts__table thead th:nth-child(3) {
        width: 220px;
    }

    .broadcasts__table thead th:nth-child(4) {
        width: 160px;
    }
}

.broadcasts__link {
    font-weight: var(--font-weight-bold);
}

.broadcasts__state {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-weight: var(--font-weight-bold);
    white-space: nowrap;
}

/* The dot agrees with the word beside it and carries nothing on its own: three states are three
 * words, and three tints would be the only difference for anybody who cannot tell them apart
 * (WCAG 2.2 AA 1.4.1). */
.broadcasts__dot {
    flex-shrink: 0;
    width: 8px;
    height: 8px;
    border-radius: var(--radius-pill);
    background: var(--nn-granite-grey);
}

.broadcasts__dot--scheduled {
    background: var(--colour-warning);
}

.broadcasts__dot--sent {
    background: var(--colour-success);
}

.broadcasts__dot--failed {
    background: var(--colour-danger);
}

.broadcast__send {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.broadcast__sealed {
    margin: 16px 0 0;
    font-size: 15px;
    line-height: 1.55;
    color: var(--colour-text-muted);
}

/* --- Confirm the send ------------------------------------------------------------------------ */
.sendcard__reach {
    margin: 14px 0 0;
    font-size: 28px;
    line-height: 1.15;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    color: var(--colour-text-inverse);
}

.sendcard__warning {
    margin: 12px 0 0;
    font-size: 15px;
    line-height: 1.55;
    color: var(--colour-text-on-primary-muted);
}

.sendcard__action {
    margin: 20px 0 0;
}

.sendcard__action .button {
    width: 100%;
    justify-content: center;
}

/* --- When sending is refused ------------------------------------------------------------------ */
.refusals__list {
    margin: 14px 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.refusals__item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 15px;
    line-height: 1.5;
    color: var(--colour-text);
}

.refusals__mark {
    flex-shrink: 0;
    margin-top: 2px;
    color: var(--board-negative-text);
}

/* --- Scheduled, and cancellable until it fires ------------------------------------------------ */
.scheduledcard__when {
    margin: 14px 0 0;
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 20px;
    font-weight: var(--font-weight-bold);
}

.scheduledcard__dot {
    flex-shrink: 0;
    width: 9px;
    height: 9px;
    border-radius: var(--radius-pill);
    background: var(--colour-warning);
}

.scheduledcard__note {
    margin: 10px 0 0;
    font-size: 15px;
    line-height: 1.55;
    color: var(--colour-text-muted);
}

.scheduledcard__action {
    margin-top: 16px;
}

/* --- A locked block, from AdminCampaign.dc.html ----------------------------------------------
 *
 * The board chips a block that can no longer move and puts the reason under it. The chip is the
 * state at a glance for somebody scanning a form for what they may change; the sentence is why,
 * for the one who then wants to know.
 */
.locked {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px 16px;
    margin: 0;
}

.locked__pair {
    min-width: 0;
    margin: 0;
}

/* THE WORD AND THE BOARD'S MARK. AdminCampaign.dc.html sets a 14px stroked padlock before
 * "Locked", in ink on the locked chip's own ground (--board-locked-ground, the token for exactly
 * this chip). It is an SVG in the text's colour; the emoji padlock this product refused stays
 * refused. The word carries the meaning (WCAG 2.2 AA 1.4.1); the mark seconds it. */
.locked__chip {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    gap: 6px;
    margin: 0;
    padding: 6px 13px;
    border-radius: var(--radius-pill);
    background: var(--board-locked-ground);
    color: var(--colour-primary);
    font-size: 13px;
    font-weight: var(--font-weight-bold);
}

.locked__mark {
    flex: 0 0 auto;
}

/* --- Competition draws, from AdminCompetitions.dc.html at 1440x1160 -------------------------
 *
 * The published result once at the top, then the three competitions side by side. Stacked
 * full-width they read as three unrelated pages; the board's row says they are three views of
 * one campaign, and each carries its own state.
 */
.competitions-admin__official {
    margin-bottom: 20px;
}

.competitions-admin__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
    /* STRETCHED, as the board draws them: three cards of one campaign, not three cards that
     * happen to be near each other. Their content differs in length by a paragraph or two and
     * a ragged row of tops reads as a layout fault. */
    align-items: stretch;
}

/* THE GAP IS THE ONLY SPACE BETWEEN THEM. `.card + .card` gives a stacked card its air, and
 * inside this grid it pushed the second and third cards 24px below the first. */
.competitions-admin__grid > .card + .card {
    margin-top: 0;
}

@media (min-width: 64rem) {
    .competitions-admin__grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.competitions-admin__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px 14px;
}

/* A WORD, AND THE TINT ONLY SECONDS IT. "Decided on Viva Engage" and "not yet" are different facts,
 * and a reader who cannot tell one chip's ground from another's still reads both (1.4.1).
 *
 * THE BOARD'S SMALL CHIP, three grounds: Not yet in ink on the tint, Drawn on the positive
 * ground, Decided on Viva Engage in the muted word on the closed grey (5.44:1). */
.competitions-admin__chip {
    flex-shrink: 0;
    margin: 0;
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    background: var(--colour-surface-field);
    color: var(--colour-text);
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    white-space: nowrap;
}

.competitions-admin__chip--drawn {
    background: var(--board-positive-ground);
    color: var(--board-positive-text);
}

.competitions-admin__chip--outside {
    background: var(--board-closed-ground);
    color: var(--colour-text-muted);
}

/* A competition this campaign is not running at all. Quieter than "not started yet", because it
 * is not waiting for anything — and the words carry that, not the tint (WCAG 2.2 AA 1.4.1). */
.competition__state--off {
    background: var(--board-closed-ground);
    color: var(--colour-text-muted);
}

.competition__state--off .competition__dot {
    background: var(--nn-granite-grey);
}

/* The second diploma, on the ink panel beside the first: the same shape, one voice quieter. */
.button--onink-quiet {
    background: none;
    border: var(--border-width-strong) solid var(--colour-text-inverse);
    color: var(--colour-text-inverse);
}

.button--onink-quiet:hover,
.button--onink-quiet:focus-visible {
    background: var(--colour-rule-on-primary);
}

/* --- The public materials page, from GuestMaterials.dc.html at 1440x1460 ---------------------
 *
 * Copy an ambassador pastes into an intranet post, with an index down the side. The blocks are
 * the page; the downloads the product also has sit under them.
 */
.matcopy {
    width: 100%;
    max-width: 90rem;
    margin: 0 auto;
    padding: 0 96px 48px;
}

.matcopy__inner {
    display: grid;
    grid-template-columns: 1fr;
    gap: 24px;
    align-items: start;
}

/* THE INDEX IS A CARD, in the top row since /materials v5 (public.css). */
.matindex {
    padding: 24px 26px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: 24px;
    background: var(--colour-surface);
}

.matindex__items {
    margin: 12px 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.matindex__item {
    display: block;
    padding: 12px 16px;
    border-radius: 14px;
    color: var(--colour-text);
    font-size: 16px;
    font-weight: var(--font-weight-bold);
    text-decoration: none;
}

.matindex__item:hover,
.matindex__item:focus-visible {
    background: var(--colour-surface-field);
}

.matcopy__blocks {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

.matblock {
    padding: 30px 34px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: 28px;
    background: var(--colour-surface);
}

.matblock__heading {
    margin: 0;
    font-size: 26px;
    line-height: 1.2;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
}

.matblock__body {
    margin-top: 14px;
}

.matblock__line {
    margin: 8px 0 0;
    font-size: 17px;
    line-height: 1.6;
    color: var(--colour-text-muted);
}

.matblock__line + .matblock__line {
    margin-top: 16px;
}

/* The downloads keep their own head, one voice quieter than the page's. */
.matshead__eyebrow {
    margin: 0 0 10px;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--colour-text-muted);
}

@media (max-width: 47.9375rem) {
    .matcopy {
        padding: 0 16px 32px;
    }

    .matblock {
        padding: 24px 22px;
    }
}

/* --- Writing the materials page, from AdminMaterials.dc.html at 1440x1220 --------------------
 *
 * The e-mail centre's three columns, with the preview and the change history sharing the right.
 */
.placeholders__note {
    margin: 8px 0 0;
    font-size: 14px;
    line-height: 1.5;
    color: var(--colour-text-muted);
}

/* SAID WHERE THE BUTTON IS. An operator who has written for an inbox expects a draft; this
 * screen does not have one, and the moment to learn that is before pressing Save. */
.publishes {
    margin: 16px 0 0;
    padding: 14px 18px;
    border-left: var(--border-width-accent) solid var(--colour-warning);
    border-radius: 0 16px 16px 0;
    background: var(--board-pending-ground);
    color: var(--board-pending-text);
    font-size: 15px;
    line-height: 1.55;
}

/* A row that is part of the page but not a destination: the dates block has no words. */
.maillist__item--static {
    display: block;
    padding: 14px 16px;
    border-radius: 16px;
    background: var(--colour-surface-warm);
    color: var(--colour-text);
}

.matpreview {
    margin-top: 14px;
    padding: 22px 24px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: 20px;
    background: var(--colour-surface);
}

.matpreview__heading {
    margin: 0;
    font-size: 20px;
    line-height: 1.25;
    font-weight: var(--font-weight-bold);
}

.matpreview__line {
    margin: 10px 0 0;
    font-size: 15px;
    line-height: 1.55;
    color: var(--colour-text-muted);
}

.matchanges {
    margin-top: 22px;
    padding-top: 20px;
    border-top: var(--border-width) solid var(--colour-rule-warm);
}

.matchanges__label {
    margin: 0;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--colour-text-muted);
}

.matchanges__rows {
    margin: 12px 0 0;
}

.matchanges__row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 6px 16px;
    padding: 8px 0;
}

.matchanges__what {
    font-size: 15px;
    color: var(--colour-text);
}

.matchanges__when {
    margin: 0;
    flex-shrink: 0;
    font-size: 14px;
    color: var(--colour-text-muted);
}

/* THE HEADING OF A RESULTS TABLE, AND THE NUMBER BESIDE IT.

   Support.dc.html states how many colleagues matched above the table rather than below it, so
   the reader knows how much there is before they start scanning. adcard__head already lays a
   title and an aside out on one line; this only separates it from the table underneath. */
.supporttable__head {
    margin-bottom: var(--space-sm);
}

/* --- The support results table, as Support.dc.html draws its rows --------------------------- */

/* A name is whole (F-043): it wraps at its spaces and hyphens and the row grows. The comment used
 * to sit INSIDE this selector, after `.board-table__row--you`, which made the rule a descendant
 * selector that matched no ordinary row (Copilot on #147, V9). */
.supporttable__who {
    min-width: 0;
    white-space: normal;
}

/* SUPPRESSED HERE, AND ONLY HERE. The shared "this row is you" treatment draws an accent bar down
 * the first cell, which is right on a leaderboard, where the row is a person's own. On this table
 * the row is a SELECTION, the board marks it with the filled disc alone, and the bar cut through
 * it. */
.supporttable .board-table__row--you > *:first-child {
    box-shadow: none;
}

/* Somebody on no team, said rather than dashed. */
.supporttable__noteam {
    color: var(--colour-text-muted);
}

/* --- The selected participant, as Support.dc.html draws the panel --------------------------- */

.selectedcard__who {
    min-width: 0;
}

.selectedcard__status {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3xs);
}

/* LABEL LEFT, VALUE RIGHT. The board sets every value against the panel's right edge, which is
 * what makes four facts of different lengths read as a column rather than as ragged prose. */
.factlist--panel .factlist__row {
    flex-wrap: nowrap;
    align-items: baseline;
}

/* THE LABEL STAYS ON ONE LINE and the value takes whatever is left. Novo's EVP areas are
 * reproduced verbatim — "CxO Office (CEO Office, Corporate Strategy, and Sustainability)" is a
 * real one — so the value is the side that must be free to wrap. Sharing the row evenly instead
 * broke "Team placement" across two lines beside a value that wrapped anyway. */
.factlist--panel .factlist__label {
    flex: 0 0 auto;
    white-space: nowrap;
}

.factlist--panel .factlist__value {
    flex: 1 1 auto;
    text-align: right;
    font-weight: var(--font-weight-bold);
}

/* The qualification sits UNDER the value it qualifies, in the board's smaller muted type: at the
 * end of the line it reads as part of the placement rather than as a note about it. */
.factlist--panel .factlist__via {
    display: block;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
}

/* THE ACTIONS READ AS SENTENCES, SO THEY ARE SET LIKE ONE. Centred labels on three stacked
 * full-width buttons give three different left edges; the board aligns them, which is what lets
 * an operator read the list rather than each button. */
.selectedcard__action {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2xs);
    text-align: left;
}

/* THE OVERSIGHT LINE, quiet on purpose: a count and two footnotes under the page's head, read
 * when somebody wants to know, never the thing the page is about. */
.oversight {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.oversight__latest {
    font-size: var(--font-size-xs);
}

/* --- The selected person's own history, and the panel before anybody is picked ------------- */

/* THE FOOT OF THE PANEL, as Support.dc.html draws it since ACC-009: a hairline, a small-capital
 * eyebrow — the board's "READ-ONLY · HISTORY ON THIS RECORD" — and the last few entries in the
 * audit trail's own format. Small capitals rather than a heading-sized title: it is the panel's
 * footnote, not its subject. */
.selectedcard__history {
    margin-top: var(--space-md);
    padding-top: var(--space-md);
    border-top: var(--border-width) solid var(--colour-rule-warm-soft);
}

.selectedcard__historyhead {
    margin: 0 0 var(--space-2xs);
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/* TWO COLUMNS FROM THE START. Before anybody is picked the panel holds the board's one line, so
 * the page keeps its shape when the first row is clicked. */
.selectedcard--empty {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 8rem;
    text-align: center;
}

.selectedcard__emptyline {
    margin: 0;
    color: var(--colour-text-muted);
}

/* --- The team card (My details) ---------------------------------------------------------------- */

.teamcard {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.teamcard__name {
    margin: 0;
    color: var(--colour-text);
    font-size: 28px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
}

/* The send control and the way into the mailbox sit in one cell, on one line where there is
 * room and stacked where there is not. */
.testaccess__send {
    display: inline;
}

/* === FINALISING THE CAMPAIGN, AS SuperOps.dc.html DRAWS IT ==================================
 *
 * One ink panel rather than a page of facts on the warm ground. See the template for why: this
 * screen happens once, cannot be undone by any ordinary means, and every competition and
 * diploma is drawn against what it records — and it read like a settings page.
 */
.finalisepage .inkpanel {
    max-width: 48rem;
}

.finalisecard__title {
    margin: 0 0 var(--space-sm);
    font-size: 36px;
    line-height: 1.1;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
}

/* The facts, on a raised step of the same ink. A white card inside the panel would read as a
 * second surface; this reads as part of the one thing the screen is about. */
.finalband {
    margin: var(--space-md) 0;
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-lg);
    background: var(--colour-surface-ink-raised);
}

.finalband__row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2xs) var(--space-md);
    padding: var(--space-2xs) 0;
    border-bottom: var(--border-width) solid var(--colour-rule-on-primary);
}

.finalband__row:last-child {
    border-bottom: 0;
}

.finalband__label {
    color: var(--colour-text-on-primary-muted);
    font-size: var(--font-size-sm);
}

.finalband__value {
    margin: 0;
    color: var(--colour-text-on-primary);
    font-weight: var(--font-weight-bold);
    text-align: right;
    overflow-wrap: anywhere;
}

.finalband__tag {
    color: var(--colour-text-on-primary-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
}

/* When there is nothing to press, the sentence saying why stands where the button would. */
.finalisecard__blocked {
    margin: var(--space-md) 0 0;
    color: var(--colour-text-on-primary-muted);
    line-height: var(--line-height-base);
}

/* --- Standing inside somebody's account, as SuperOps.dc.html draws it ------------------------ */

/* "· read-only", on the banner. The board says it in the bar rather than only in a sentence
 * further down, so an operator glancing at a tab knows in one word what they are in. */
.impersonation__tag {
    color: var(--colour-text-on-primary-muted);
    font-weight: var(--font-weight-regular);
}

/* AND WHY THE FORMS ARE STILL THERE. See the partial: the fields are the participant's own and
 * the refusal is in the server, which is not something looking at the screen can tell you. Its
 * own strip under the banner, because it is true of every screen the episode can reach. */
.impersonation__locked {
    margin: 0;
    padding: var(--space-2xs) var(--space-md);
    background: var(--colour-surface-field);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: var(--line-height-base);
}

.impersonation__locked-heading {
    color: var(--colour-text);
}

/* === THE FOOTER SITS AT THE BOTTOM OF A SHORT PAGE ==========================================
 *
 * A confirmation screen is one card and a question. On a 1220px window that left the footer
 * halfway up, with a third of the window as bare warm ground underneath it — which reads as a
 * page that failed to finish loading rather than as a page with little on it. Every
 * confirmation, every empty state and every refusal in the product is a short page.
 *
 * THREE SHELLS ALREADY DID THIS on their own wrapper — .adminpage, .gateshell and .errorshell
 * each carry min-height and a column. The participant shell had no wrapper to carry it, which
 * is why it was the one that did not. Putting it on <body> covers all four and means the next
 * layout is right the day it is written.
 */
body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* Whatever the shell puts between the bar and the footer takes the slack. `flex: 1 0 auto`
 * rather than `1 1 auto`: a long page must still be allowed to be longer than the window. */
body > .page,
body > .adminpage,
body > .gateshell,
body > .errorshell,
body > main {
    flex: 1 0 auto;
}

/* A state, not a control. CaptainActions.dc.html marks a refusal with a quiet pill where a
 * button would otherwise sit, so the screen says "this is not possible" rather than showing
 * something greyed out that looks as though it might become possible. */
.gatecard__state {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3xs);
    margin: var(--space-sm) 0;
    padding: 6px 14px;
    border-radius: var(--radius-pill);
    background: var(--colour-surface-badge);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

/* The way onward and the way to ask sit on one line. */
.gatecard__note {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
}

/* How long somebody has to start a team, on the band that asks them to. Quiet, because it
 * qualifies the button rather than competing with it. */
.noteam__until {
    margin: 0 0 var(--space-sm);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* The total, under a hairline: it is the sum of the two rows above rather than a third one. */
.confirm__split-row--total {
    border-top: var(--border-width) solid var(--colour-border-soft);
    padding-top: var(--space-2xs);
    margin-top: var(--space-2xs);
    font-weight: var(--font-weight-bold);
}

/* A refusal about a control this activity does not draw. It has no field to sit beside, so it
 * sits at the head of the band — the one exception to the rule the band otherwise follows. */
.converter__refusal {
    margin-bottom: var(--space-2xs);
}

/* --- The converter band when it has refused something ---------------------------------------
 *
 * The messages stand beside their own fields, which is what StepsStates.dc.html asks for and
 * what aria-describedby points at. Two things had to be true for that to work: the field must
 * actually CONTAIN its message — see the partial, where three <p> wrappers became <div>,
 * because a <p> inside a <p> is closed by the browser and the message became a sibling of the
 * control — and a message under a 132px duration box must not wrap onto three lines and drag
 * the answer and the button out of the row with it.
 */
/* ONLY WHERE THE ROW IS ACTUALLY A ROW.
 *
 * Below 48rem every converter field is full width and they stack with a 16px gap — and an
 * absolutely positioned message is ~29px of text at the default size, more when it wraps, more
 * again at 200% zoom or under the 1.4.12 text-spacing overrides. It was painted straight across
 * the label of the field beneath it, so a participant on a phone could read neither the refusal
 * nor the thing it was about. Taking a field out of flow to protect a row's alignment only
 * makes sense while there is a row; below that width the message goes back in the flow and
 * pushes the stack down, which is what it should have done all along. Review found it. */
@media (min-width: 48rem) {
    .converter__row .field__error {
        position: absolute;
        top: 100%;
        left: 0;
        width: max-content;
        max-width: 18rem;
        margin-top: var(--space-3xs);
    }

    .converter__row .field {
        position: relative;
    }

    /* Tops aligned, so one field carrying a message does not push the labels beside it down. */
    .converter__row {
        align-items: flex-start;
    }

    .converter__row .field__label {
        min-height: 1.4em;
    }
}

/* A refused band reserves the line its messages stand on, so they do not fall across the note
 * underneath. Only when something was refused: the band is otherwise as tight as the board. */
@media (min-width: 48rem) {
    .converter--refused .converter__row {
        margin-bottom: 2.25rem;
    }
}

/* Which days the question is about, said in a word beside the date. The high ones carry the
 * workspace's amber; the rest say they are unchanged and stay quiet. */
.confirm__day-date {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2xs) var(--space-sm);
}

.confirm__day-flag {
    color: var(--colour-accent-on-surface);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.confirm__day-flag--quiet {
    color: var(--colour-text-muted);
    font-weight: var(--font-weight-regular);
    letter-spacing: normal;
    text-transform: none;
}

/* (MY STEPS ON A PHONE moved to the PARTICIPANT 2026 section at the end of this sheet: the 2026
 * phone board keeps the heading and draws two cards rather than three tiles.) */

/* === THE GUEST BAR ON A PHONE ===============================================================
 *
 * The bar carries a mark, two destinations and the language switch on one row. At 390 that row
 * is 440px wide, so the switch sat 74px past the right edge of the window and the whole page
 * scrolled sideways to reach it — the one thing a phone layout must never do.
 *
 * MobileFamily.dc.html draws the same bar as the mark on the left and "DA / EN" on the right,
 * with the destinations inside the card rather than in the bar. So the row wraps: the mark and
 * the switch keep the line, and anything else goes underneath.
 *
 * SIX ROUTES, NOT ONE (ACC-001). This was written for the landing page, which was the only
 * screen whose bar had anything in it; now every guest screen carries the same two destinations
 * and would have overflowed the same way.
 */
@media (max-width: 47.9375rem) {
    /* 96px OF SIDE PADDING ON A 390px SCREEN. That is the board's figure at 1440 and it left
     * 198px for a row whose contents are 440 wide, so the switch sat off the edge and the page
     * scrolled sideways. The phone gutter is 18, like every other shell at this width. */
    .gatebar--shared .gatebar__inner {
        padding-inline: 18px;
        flex-wrap: wrap;

        /* 8px BETWEEN THE MARK AND THE PILL, NOT 16. At 320 the row has 284px to give; the
         * wordmark is 151 at the board's 17px and the pill is 122, so a 16px gap made 289 and
         * the two wrapped onto separate lines. MobileFamily.dc.html draws them sharing the top
         * line, and now they are the only two things on it. */
        gap: 8px;

        /* 4px ABOVE AND BELOW. The bar's two controls are 48px tall because Foundations.dc.html
         * sets that floor for a phone target, and this row inherited --space-2xs top and bottom
         * from the desktop rule, which made the bar 74. Four and four around the 48 make 56, the
         * floor intact; the FOUNDATION 2026 block raises the row to the 2026 board's 58 and
         * centres the controls in it. */
        padding-block: 4px;
        min-height: 0;
    }

    /* THE DESTINATIONS ARE GONE FROM HERE. (The bar's phone height is the 2026 Foundation's 58px
     * now, set in the FOUNDATION 2026 block at the end of this sheet.)
     *
     * The shared bar carried "Campaign materials" and "Sign in" on a second row below 48rem,
     * which made it 130px of a 568px screen — a quarter of the fold, above the primary action,
     * for two links that belong at the end of a page. Keeping them was right while they had
     * nowhere else to go: four of the six guest routes have no card content and no navigation
     * of their own, so dropping them would have left those screens with none at all.
     *
     * Since §4b (Kenneth 25 Sep 16:35) the footer is brand only, and the phone bar shows one
     * destination again, "Sign in" as a small pill beside the language: the BRAND-ONLY FOOTERS
     * block at the end of this sheet overrides this rule. Desktop is unchanged: the bar is 72px
     * with both links (2026). */
    .gatebar--shared .gatebar__end {
        display: none;
    }

    /* THE TROUGH HUGS ITS BUTTONS AT THIS WIDTH (written for the old 56px bar; in the 58px row
     * the FOUNDATION 2026 block centres them, 5px above and below).
     * The pill draws a 4px surround on desktop, where its segments are 44px; on a phone the
     * segments are 48 because Foundations.dc.html raises the floor there, so surround plus
     * segment is 56 on its own and the bar could not be 56 with anything above or below it.
     * The surround goes rather than the target: 48 + the row's 4 and 4 is exactly 56. */
    .gatebar--shared .language__options {
        padding: 0;
    }

    /* ONE LINE FOR THE MARK AND THE SWITCH, as the board draws the phone bar; the destinations
     * go underneath.
     *
     * THE <nav> KEEPS ITS BOX. This was `display: contents` on the group, needed only because
     * the language form sat inside the <nav> and had to stay on the first row while the links
     * wrapped to the second. Removing an element's box can take it out of the accessibility
     * tree, and that element is a labelled navigation landmark — so the form moved out of the
     * <nav> instead, and both are ordinary flex children that wrap as units. */
    /* NO `order` HERE ANY MORE. The form precedes the <nav> in the markup, which is the phone's
     * own reading order — mark and pill on the top row, destinations underneath — so DOM order
     * and visual order agree at the width this product is built for, and a keyboard user no
     * longer tabs down to the second row and back up to the first. The desktop query does the
     * reordering instead, where it is a hop along one row. */

    /* THE TWO DESTINATIONS SHARE THE SECOND ROW. There was a rule here giving the first of them
     * `flex-basis: 100%` so it took a row of its own, written as `.gatebar__inner > .gatebar__link`
     * — a child selector that matched nothing, because `display: contents` removes the group's
     * box and not its place in the DOM. It had been dead since it was written.
     *
     * IT IS DELETED RATHER THAN REPAIRED. Making it work puts each link on its own line and the
     * bar becomes 186px of a 844px phone. Two rows is what the landing page has actually been
     * shipping, it keeps both destinations reachable, and MobileFamily.dc.html's phone bar —
     * mark left, DA/EN right, destinations in the card rather than the bar — is a different
     * composition that ACC-001 did not authorise and "one identical header" argues against. */

    /* THE HEADLINE IS THE BOARD'S, NOT THE LAPTOP'S. --font-size-display clamps up to 4.5rem,
     * which on 354px of content sets "Join STEP COUNT" as three lines 78px tall apiece — a
     * quarter of the phone spent on two words. MobileFamily.dc.html sets it at roughly 28. */
    .gateshell--landing .gatecard__head h1 {
        font-size: 34px;
        line-height: 1.08;
    }
}

/* === A FOCUSED CONTROL IS NEVER UNDER THE FIXED BAR =========================================
 *
 * WCAG 2.2 AA 2.4.11 Focus Not Obscured. The tab bar is 82px of fixed chrome at the bottom of
 * every phone screen and the impersonation banner is sticky chrome at the top, so a control the
 * browser scrolls flush to either edge lands behind them — focus is somewhere the reader cannot
 * see. `.sitefoot { padding-bottom }` only covers the end of the document.
 *
 * IT MATTERED MORE AFTER THE DAY LIST WAS BUILT. The phone grid used to hold one day; it now
 * holds fourteen rows, each its own link, all of them above that bar. Review found it.
 *
 * scroll-padding is the whole fix: it tells the browser how much of the viewport is not really
 * available, and every scroll-into-view — keyboard focus, fragment navigation, the row links'
 * own anchors — respects it.
 */
@media (max-width: 47.9375rem) {
    html {
        scroll-padding-block-end: 90px;
    }
}

/* The banner is sticky at every width while an episode is open, so its allowance is not scoped
 * to the phone. 54px is its own height plus the read-only strip beneath it. */
html:has(.impersonation) {
    scroll-padding-block-start: 54px;
}

/* === THE TABLET BAND, FROM TabletSteps.dc.html (ACC-012) ====================================
 *
 * Between 48rem and 64rem the step screen drew the laptop's converter: one flex row of controls
 * at 132 and 180, the answer and the button pushed in beside them, and no rule. The tablet board
 * draws a different composition — three controls on a `1fr 120px 150px` grid, a hairline that
 * closes them, and the answer and the button on their own line beneath it — and the board is the
 * specification. `TabletSteps.dc.html:107-131`.
 *
 * THE TABLET COMPOSITION RUNS TO 1279, WHOLE (advisor, 2026-09-23). The boards draw two
 * compositions, 1024 and 1440, and nothing between them; a width band takes one of them entirely,
 * never a mix. The day grid is already four across from 64rem to 80rem, so the band follows it:
 * tablet from 48rem up to 79.9375rem, the laptop row from 80rem. Every `min-width: 64rem`
 * converter rule above this also matches up to 1279, so this block has to come after them and win
 * there — the seam is recorded in locked-design-system.md.
 *
 * A GRID, NOT THE FLEX ROW WITH NEW WIDTHS. The answer has to cross all three columns under the
 * rule, and `.converter__answer` — `display: contents` on the laptop — becomes a real box here
 * that spans the grid, as it is on the phone.
 */
@media (min-width: 48rem) and (max-width: 79.9375rem) {
    .converter__row {
        display: grid;
        /* The qualifier column is 180 so the longest option ("Bære golfudstyr", 129px) fits
         * without resizing the row (the converter brief, item 5). */
        grid-template-columns: 1fr 120px 180px;
        gap: 12px;
        align-items: start;
        margin-top: 14px;
    }

    .converter__row .converter__field,
    .converter__row .converter__field--narrow,
    .converter__row .converter__field--qualifier {
        width: auto;
        min-width: 0;
        flex: none;
    }

    .converter .field__label {
        margin-bottom: 7px;
    }

    .converter .field__select,
    .converter .field__withunit {
        height: 52px;
        padding: 0 14px;
    }

    /* THE RULE AND THE LINE UNDER IT. The board puts 14px between the controls and the rule; the
     * grid's row gap is already 12 of those. */
    .converter__answer {
        grid-column: 1 / -1;
        display: flex;
        align-items: flex-end;
        justify-content: space-between;
        gap: 16px;
        flex-wrap: wrap;
        margin-top: 2px;
        padding-top: 14px;
        border-top: var(--border-width) solid var(--colour-rule-on-tint);
    }

    /* The same guard as the phone's: the figure keeps its content width and never runs under the
     * button, and a band too narrow for both wraps instead. */
    .converter__result {
        flex: 1 1 auto;
        min-width: min-content;
        min-height: 0;
        padding-left: 0;
        border-left: 0;
    }

    /* The equals belongs to the laptop row, where the controls are to its left. */
    .converter__equals {
        display: none;
    }

    .converter__result-body {
        padding-left: 0;
        background: none;
    }

    .converter__result-label {
        font-size: 13px;
        margin-bottom: 2px;
    }

    .converter__result-value {
        height: auto;
        font-size: 38px;
        line-height: 1.05;
    }

    /* A REFUSAL STANDS IN THE FLOW HERE. Above 48rem the messages are lifted out of it so they do
     * not drag the laptop row's answer and button down; in this band the answer has its own line
     * under the controls, so a lifted message would be painted across the rule and the figure.
     * In the flow it pushes that line down instead, which is what it is for. */
    .converter__row .field__error {
        position: static;
        width: auto;
        max-width: none;
    }

    .converter--refused .converter__row {
        margin-bottom: 0;
    }

    /* AND A ROW HOLDING A MESSAGE STACKS, as the phone's pair does (item 4 below). In the 120px
     * column "Angiv minutter som et helt tal, for eksempel 30." wrapped to four lines, 99px — the
     * same defect this brief found at 390, recreated by this brief's own grid. Driven at 768 and
     * 1024.
     *
     * KEYED ON THE MESSAGE, NOT ON `.converter--refused`. The script clears a qualifier's message
     * when the activity changes but can leave the band's class behind, and a class-keyed rule
     * kept the row stacked with nothing in it. Found in design review. After the two-column rule
     * above, which has the same specificity. */
    .converter__row:has(.field__error) {
        grid-template-columns: 1fr;
    }
}

/* A REFUSED DURATION ON A PHONE TAKES THE WHOLE LINE (ACC-012 item 4). At 390 the duration sits
 * in a 108px column beside the question, and its message — "Angiv minutter som et helt tal, for
 * eksempel 30." — wrapped to five lines and 124px there. While the row holds a message the pair
 * stacks full width, so each message reads as a sentence under its own control. Keyed on the
 * message rather than the band's class, for the reason given in the tablet block above. */
@media (max-width: 47.99rem) {
    .converter__row:has(.field__error) .converter__field--narrow,
    .converter__row:has(.field__error) .converter__field--qualifier {
        flex-basis: 100%;
    }
}

/* THE QUALIFIER WITH NOTHING TO ASK (F-050).
 *
 * From 48rem the boards draw the row as four columns in every state, so the control stays in
 * its column, disabled, saying why. It is the component sheet's disabled field
 * (SharedStates.dc.html, Foundations.dc.html): `--colour-disabled-surface` and
 * `--colour-disabled-text` on the warm edge `.field__select:disabled` already gives it. That
 * rule's own ground is the band tint since item 12 (2026-10-05).
 * (On /steps since the v4 journey walk the disabled qualifier and the days not yet reached both
 * take the v4 band tint instead: see the My steps v4 block.)
 *
 * ON A PHONE IT IS NOT DRAWN. MyStepsMobile.dc.html pairs the duration with the question on
 * one line; with no question the duration takes that line alone, as it did before this
 * change, and a disabled control there would only take width from it. */
.converter .field__select:disabled {
    background: var(--colour-disabled-surface);
    color: var(--colour-disabled-text);
    opacity: 1;
    cursor: not-allowed;
    /* No chevron: it promises a list this control does not have, and its 20px are what let the
     * reason fit the tablet's 150px column. The strings are short for the same reason —
     * "Vælg aktivitet" is 112px at 16px against a 120px content box. */
    appearance: none;
}

/* THE PHONE SHOWS STEP 3 DISABLED UNTIL AN ACTIVITY IS CHOSEN, as a computer does, so the
 * calculation reads 1-2-3 at every width (advisor 2026-10-05 03:30; it was hidden here). */
@media (max-width: 47.99rem) {
    /* THE RING STANDS 3px OUTSIDE THE DURATION'S BOX, AS AT EVERY OTHER WIDTH. The focus ring is
     * the input's own outline (3px, offset 3), and the input kept its 50px inside the phone's
     * 48px wrapper, so the ring stood 7px above and below the box. 42 is the wrapper less 3 on
     * each side, which is where the ring sits on the laptop's 56 with its 50px input. Drawing
     * the ring on the wrapper, as the board does, is ACC-006's open "ring on the minutes
     * wrapper" item and every width's change, not this one's. */
    .converter .field__withunit .field__input {
        height: 42px;
        min-height: 0;
    }
}

/* THE ANSWER HOLDS ITS PLACE WHEN A FIGURE ARRIVES (F-050). The row's answer took its content's
 * width, so the dash's 88 grew to 124 for "3 662" and the activity, the duration and the
 * question slid 36px left under the participant's caret. 124 is a four-digit figure at 42px,
 * which is what a typical activity gives and what the board's 3 240 measures, so the 1440 row
 * stays MySteps.dc.html's `437 132 180` answered and now also empty. A five-digit answer still
 * widens it; reserving that would narrow the board's own row. */
@media (min-width: 80rem) {
    .converter__row .converter__result-body {
        min-width: 124px;
    }
}

/* A GATE FORM WHOSE FIRST VISIBLE CONTROL IS ITS BUTTON STANDS IT 24px BELOW THE LEDE (ACC-002).
 *
 * The family's rhythm under the lede is 24px to the first visible thing: on /sign-in that is the
 * label, whose own `margin-top: 24px` says so. `/auth/{token}` has no field — its form is two
 * hidden inputs and the button — so the first visible thing is the button, and the 16px it
 * carries is the gap it keeps under an input, not under a lede. The match is structural — a
 * button whose previous sibling is a hidden input — which today is only that form. A future gate
 * form that put a hidden input between a visible field and its button would take the 24 too.
 *
 * Not the onboarding family, which sets its own 22 above the action on purpose
 * (`.gatecard--onboarding .gate__form .button`) and has a join confirmation of the same shape. */
.gatecard:not(.gatecard--onboarding) .gate__form > input[type="hidden"] + .button {
    margin-top: 24px;
}

/* A GATE HEADING WRAPS A NAME WITH NO SPACES IN IT (ACC-002, design review). The invited
 * continue screen, the join link and the join confirmation all print a team name inside the
 * heading — participant-authored, up to eighty characters, and permitted to contain no whitespace
 * at all. At 34px bold on a 390 phone about fifteen unbroken characters ran past the card's edge
 * and scrolled the page sideways (WCAG 2.2 1.4.10). The same rule every other place this product
 * prints a team name already carries; it changes nothing for text that fits. */
.gatecard h1 {
    overflow-wrap: anywhere;
}

/* === THE ADMIN SHELL, GROUPED (ACC-009) ========================================================
 *
 * AdminOverview.dc.html, AdminCampaign.dc.html and Support.dc.html draw one bar: 84px of ink, a
 * `1fr auto 1fr` grid with the mark left, the five groups centred and the operator right; under it,
 * on a group with more than one page, a 56px white row of quiet tabs; and an ink footer that is
 * the brand only — the way back to the participant pages is in the bar (2026-09-27).
 *
 * DESKTOP ONLY, AS DECIDED (2026-09-22): the grid and the fixed heights are from 80rem. Below it
 * the bar keeps the wrapping flex row above — a plain stacked fallback that does not break, and is
 * not designed. */
@media (min-width: 80rem) {
    .adminshell .adminbar,
    .adminshell .adminbar__inner {
        min-height: 84px;
    }

    .adminshell .adminbar__inner {
        display: grid;
        grid-template-columns: 1fr auto 1fr;
        column-gap: 24px;
    }

    .adminshell .adminbar__mark {
        margin-right: 0;
    }

    .adminshell .adminbar__who {
        justify-self: end;
        white-space: nowrap;
    }
}

/* The second level: quiet pill tabs, the board's `.sub` — 14px 600 muted, the current one on the
 * tint in ink and 700. */
.adminsub {
    background: var(--colour-surface);
    border-bottom: var(--border-width) solid var(--colour-rule-warm);
}

.adminsub__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    padding-inline: max(var(--space-md), (100% - var(--shell-measure)) / 2);
    padding-block: var(--space-3xs);
}

.adminsub__link {
    padding: 8px 14px;
    border-radius: var(--radius-pill);
    color: var(--colour-text-muted);
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
    text-decoration: none;
}

.adminsub__link:hover {
    color: var(--colour-text);
}

.adminsub__link--on {
    background: var(--colour-surface-field);
    color: var(--colour-text);
    font-weight: var(--font-weight-bold);
}

@media (min-width: 80rem) {
    /* The bar's own 64px gutter, so bar, row, page and footer share one left edge. */
    .adminsub__inner {
        min-height: 56px;
        padding-block: 0;
        padding-inline: 64px;
    }
}

/* The bar's own numbers, from the design system's "Administration — always an ink bar": links
 * `11px 18px` at 15px; the person cluster `16px` apart and never wrapping. */
@media (min-width: 80rem) {
    .adminshell .adminnav__link {
        padding: 11px 18px;
    }

    .adminshell .adminbar__who {
        gap: 16px;
    }

    /* The footer is 62px of ink on the bar's own 64px gutters. */
    .adminshell .adminfoot {
        max-width: none;
        min-height: 62px;
        padding-block: 0;
        padding-inline: 64px;
    }
}

/* The second row sits directly under the bar. `.adminpage` spaces its children with a flex gap,
 * which put 32px of ground between the two; the row is part of the bar, not a section below it. */
.adminsub {
    margin-top: calc(-1 * var(--space-lg));
}

/* THE CLUSTER NEVER WRAPS (the board's rule), and a centred menu leaves it one third of the bar
 * less half the menu. The chip and Sign out keep their size; the name is whole or not drawn —
 * see "A NAME IS WHOLE OR NOT DRAWN" below. */
@media (min-width: 80rem) {
    .adminshell .adminbar__inner {
        grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    }

    .adminshell .adminbar__who {
        min-width: 0;
        max-width: 100%;
    }

    .adminshell .adminbar__role,
    .adminshell .adminbar__out {
        flex-shrink: 0;
    }
}

/* BETWEEN 1280 AND 1439 THE MENU'S LINKS TIGHTEN, so the name keeps some room. The boards draw
 * the bar at 1440 only, with `18px` sides on each link; at 1280 the same five links left the
 * person cluster about 230px for chip, name and Sign out with Arial, and less with a wider face.
 * `12px` sides give each side of the bar 30px back. From 1440 the board's own numbers apply. */
@media (min-width: 80rem) and (max-width: 89.9375rem) {
    .adminshell .adminnav__link {
        padding-inline: 12px;
    }
}

/* A NAME IS WHOLE, ON ONE LINE, OR NOT DRAWN (F-043, advisor 2026-09-23). A person's name in
 * either bar is never shortened with an ellipsis and never wrapped. Both bars show the person's
 * initials. In the participant bar the name is drawn beside them from 1440, and only when it fits
 * one line — which the server estimates from the name's letters (App\Support\BarName) and marks
 * with `--long` when it does not. The admin bar draws the name for nobody from 48rem (option A,
 * 2026-09-27: the way to the participant pages took its room); see admin.css.
 * Wherever it is not drawn it stays in the accessibility tree, visually hidden rather than
 * removed, because the initials are aria-hidden and would otherwise leave the person unnamed;
 * the whole name is on hover, from the cluster's `title`.
 *
 * It replaces "the name gives way", which shortened the name to fit a capability holder's seven
 * links at 1280 (F-026), and a first cut of this rule that wrapped a long name at 1440. */
.appbar .whoami--long .whoami__body {
    display: block;
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

@media (max-width: 89.9375rem) {
    .appbar .whoami__body,
    .adminshell .adminbar__name {
        display: block;
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }
}

/* THE ADMIN BAR'S INITIALS, as the participant bar's: a circle beside the role chip, so an
 * operator who switches accounts sees who they are at every width. White on the ink bar. */
.adminshell .adminbar__initials {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    /* 32px, the participant bar's size; 34 from 1440 for a long name, the only case the initials
     * are still drawn there (the FOUNDATION 2026 block hides them where the name is shown). */
    width: 32px;
    height: 32px;
    border-radius: var(--radius-pill);
    background: var(--colour-surface);
    color: var(--colour-primary);
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-caps);
}

@media (min-width: 90rem) {
    .adminshell .adminbar__initials {
        width: 34px;
        height: 34px;
    }
}

/* BETWEEN 1280 AND 1439 THE LINKS TIGHTEN, as the admin bar's do: the board draws the bar at 1440
 * only, and at 1280 a captain holder's seven links left the name a few pixels. `12px` sides give
 * back 56px across the row. From 1440 the board's own `16px` apply. */
@media (min-width: 80rem) and (max-width: 89.9375rem) {
    .appbar .bar__link {
        padding-inline: 12px;
    }
}

/* === THE OVERVIEW, THREE BLOCKS IN ONE COLUMN (ACC-009) =====================================
 *
 * AdminOverview.dc.html: Needs attention, The campaign today, What comes next — one card style,
 * one column rhythm. The figures panel used to share its row with a narrow ink column holding the
 * schedule and a card of shortcuts; the shortcuts went (every function is in the menu) and the
 * schedule became the third block, a white panel like the other two. */

/* WHILE SIGN-UPS ARE OPEN THE ROW HOLDS SIX, three by two. Six across would leave each figure
 * about 200px at 1440, narrower than a nine-digit total at 44px. */
@media (min-width: 64rem) {
    .statrow--six {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        row-gap: 28px;
    }

    .statrow--six .statcard:nth-child(3n + 1) {
        padding-left: 0;
        border-left: 0;
    }

    .statrow--six .statcard:nth-child(3n) {
        padding-right: 0;
    }
}

/* THE EXACT TOTAL FITS ITS OWN COLUMN, WHATEVER THE LAYOUT. A ten-digit total is about 7.6 times
 * its font size wide, and the column it gets runs from about 180px on a 320px phone to 173px in
 * the four-column row at 1024px and 280px at 1440px — so the size is taken from the column, not
 * the viewport: 34px wherever that fits, smaller only where it does not. Measured from 320 to
 * 1440 in both the four- and the six-figure row. */
.campfigures .statcard {
    container-type: inline-size;
}

.campfigures .statcard__value--long {
    font-size: min(34px, 100cqi / 8);
}

/* ONE COLUMN BELOW 48rem. The base rule's auto-fit track was still in force there and gave three
 * columns of about 210px at 767px. Stacked, the figures have no rule beside them, so the side
 * padding that spaced them from one only narrows the column. */
@media (max-width: 47.9375rem) {
    .statrow {
        grid-template-columns: minmax(0, 1fr);
    }

    .statcard {
        padding-inline: 0;
    }
}

/* The "%" beside a percentage, smaller and muted as the board sets it. */
.statcard__unit {
    font-size: 24px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0;
    color: var(--colour-text-muted);
}

/* What comes next: label, date, and the screen where it is set, one row each, a hairline
 * between rows. The board's widths: the label takes the room, the link a fixed 200px column. */
.schedulecard__rows {
    margin: 22px 0 0;
}

/* THE DATE COLUMN IS CAPPED, NOT auto. The result row's "when" is a sentence rather than a date,
 * and an auto track sized it to its whole length, leaving the label a 0px column to be painted
 * over at 390px. fit-content() lets it wrap inside its share instead. */
.schedulecard__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) fit-content(50%);
    align-items: baseline;
    gap: 8px 24px;
    padding: 16px 0;
    border-top: var(--border-width) solid var(--colour-rule-warm-soft);
}

.schedulecard__row:first-child {
    padding-top: 0;
    border-top: 0;
}

.schedulecard__row:last-child {
    padding-bottom: 0;
}

.schedulecard__what {
    font-size: 18px;
    font-weight: var(--font-weight-bold);
}

.schedulecard__when {
    margin: 0;
    font-size: 16px;
    color: var(--colour-text-muted);
    font-variant-numeric: tabular-nums;
}

/* The card's one link, at its foot. The attention row indents its action past its icon; this link
 * has no icon. And at 320px "Kampagneindstillinger →" is wider than the card, so the arrow may drop
 * below the word rather than run past the card's edge. */
.schedulecard__foot .attention__action {
    margin-left: 0;
    max-width: 100%;
    flex-wrap: wrap;
}

/* --- The button system (F product group B) ------------------------------------------------------
 *
 * Foundations.dc.html draws three buttons and one disabled ground, and every button in the product
 * is one of them:
 *
 *   .button                     Primary     — ink fill, white 16px bold, 52.
 *   .button.button--main        Primary 56  — the action the screen is for: a gate card's one
 *                                             button, the landing's entry row, a full-width save,
 *                                             an error card's way on, a publish.
 *   .button.button--secondary   Secondary 52 — white, a 2px ink edge.
 *   .button.button--quiet       Quiet 44    — white, a 1px #6675A3 edge, 15px. A quiet action
 *                                             inside a row.
 *   .button:disabled            Disabled 52 — #F1EEE9, #4D5E93 text, no edge.
 *
 * WHY 56 IS A ROLE AND NOT THE PRIMARY'S HEIGHT. locked-design-system.md's height table gives 56
 * to the action a screen is for and 52 to "every other button, primary or secondary", and the
 * boards follow it: an editor's Save, a support action, a confirmation's yes and the no-team
 * card's "Create a team" are 52px fills, while GuestAuth's, MyDetails' and AdminCampaign's saves
 * are 56. A primary at 56 everywhere would have opened a gap on every one of the former.
 *
 * On ink, .button--onink is the primary (a white fill) and .button--onink-quiet the outline,
 * which takes #C9D6F0 rather than white. Destructive actions are never red-filled (decision
 * 2026-09-23): they are a secondary or a quiet button whose words say what happens.
 *
 * LAST IN THE FILE, AND THE HEIGHT IS STATED ONLY HERE. Before this section a button's height
 * was whatever the last rule about its container said — 40, 44, 46, 48, 50, 54, 58, 60, 62 and
 * 64 were all live — so the variant a call site asked for did not decide how it looked. Those
 * container rules no longer set a height, and a later rule of the same weight cannot undo this
 * one. The exception is the converter's add button, which stands in a row of 56px fields and
 * takes their height (its own rule, F-050).
 *
 * MIN-HEIGHT, NOT HEIGHT, so a label that wraps at 320px grows its button instead of spilling
 * out of it. A flex box, so a one-line label sits in the middle.
 *
 * Mobile-first: the phone values are the base and 40rem, where .button stops filling its line,
 * is where the desktop heights start. On a phone every primary is 52 (MobileFamily.dc.html) and
 * the quiet button rises to the 48px floor. `tests/Unit/ButtonsUseTheSystemTest.php` fails on a button
 * that wears none of these classes. */
.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: auto;
    min-height: var(--button-height-secondary);
    padding-block: 0;
    border: var(--border-width-strong) solid var(--colour-primary);
    border-radius: var(--radius-pill);
    background: var(--colour-primary);
    color: var(--colour-text-on-primary);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
}

.button--secondary {
    min-height: var(--button-height-secondary);
    border: var(--border-width-strong) solid var(--colour-primary);
    background: var(--colour-surface);
    color: var(--colour-primary);
}

.button--quiet {
    min-height: var(--touch-target-phone);
    border: var(--border-width) solid var(--colour-border-field);
    background: var(--colour-surface);
    color: var(--colour-primary);
    font-size: var(--font-size-sm);
}

.button--secondary:hover,
.button--quiet:hover {
    background: var(--colour-surface-field);
}

/* On ink. The white fill keeps the ink word; the outline is the boards' #C9D6F0, which is 10.82:1
 * on True Blue and 7.76:1 on the raised ink (tokens.css), where a white edge was louder than the
 * word it bounded. */
.button--onink {
    border-color: var(--colour-surface);
    background: var(--colour-surface);
    color: var(--colour-primary);
}

.button--onink-quiet {
    border: var(--border-width-strong) solid var(--board-on-ink-muted);
    background: transparent;
    color: var(--colour-text-inverse);
}

.button--onink:hover {
    border-color: var(--colour-text-on-primary-muted);
    background: var(--colour-text-on-primary-muted);
}

.button--onink-quiet:hover {
    background: var(--colour-rule-on-primary);
}

.button:disabled,
.button[aria-disabled='true'] {
    min-height: var(--button-height-secondary);
    border-color: var(--colour-disabled-surface);
    background: var(--colour-disabled-surface);
    color: var(--colour-disabled-text);
    cursor: not-allowed;
}

/* THE LARGE BUTTON (the sheet's .lg; advisor 2026-10-05 11:30): 56 tall from 40rem, its label 17px,
 * kept for Save on My steps (the front doors are twins at 48 since audit 1006, D5). Every
 * other button is the sheet's 48, .button--main included: "the action a screen is for" is said by
 * its fill and its place, no longer by extra height. */
.button--lg {
    font-size: var(--font-size-button-main);
}

@media (min-width: 40rem) {
    .button--lg {
        min-height: var(--button-height-primary);
    }

    .button--quiet {
        min-height: var(--button-height-quiet);
    }

    .button:disabled,
    .button[aria-disabled='true'] {
        min-height: var(--button-height-secondary);
    }
}

/* --- Screen pass, batch 1 (advisor, 2026-09-24 21:50) ------------------------------------------ */

/* 3: a pill's label never wraps inside its pill. Between 80 and 88rem four columns do not fit
 * the panel, so an invitation takes the three lines it has below 80rem: the address, the state
 * beside the date, then its two actions side by side. */
.roster-table__action {
    white-space: nowrap;
}

@media (min-width: 80rem) and (max-width: 87.999rem) {
    .roster-table--invites,
    .roster-table--invites tbody {
        display: block;
    }

    .roster-table--invites thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
    }

    .roster-table--invites .roster-table__row {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 8px 12px;
        padding: var(--space-xs) 0;
        border-bottom: var(--border-width) solid var(--colour-surface-field);
    }

    .roster-table--invites td {
        display: block;
        padding: 0;
        border-bottom: 0;
    }

    .roster-table--invites .roster-table__address {
        grid-column: 1 / -1;
        min-width: 0;
    }

    .roster-table--invites .roster-table__when {
        text-align: right;
    }

    .roster-table--invites .roster-table__action-cell {
        grid-column: 1 / -1;
        text-align: left;
    }

    .roster-table--invites .roster-table__actions {
        flex-direction: row;
        justify-content: flex-start;
        align-items: center;
    }
}

/* 4: stacked roster rows keep their one action under the name, and the captain's dash goes. */
@media (max-width: 79.999rem) {
    .roster-table:not(.roster-table--invites) .roster-table__action-cell {
        text-align: left;
    }

    .roster-table:not(.roster-table--invites) .roster-table__actions {
        justify-content: flex-start;
    }

    .roster-table td.roster-table__action-cell--empty {
        display: none;
    }
}

/* 7: navy, like every other text link on the page, and underlined under the pointer or focus. */
.place-change__summary {
    color: var(--colour-text);
}

.place-change__summary:hover,
.place-change__summary:focus-visible {
    text-decoration: underline;
}

/* 9: a figure column's heading ranges right over its figures, to the same edge. */
.board-table th.board-table__figure {
    padding-right: 0;
    text-align: right;
}

/* 11: the title starts where every other page's does, and a fact's detail sits under its label. */

.competition__fact-detail {
    margin-left: 0;
}

/* 14: the novohealth mark has its own middle track when the language switch takes the right
 * edge. A footer without the switch (guest, error) gives the mark the right edge, as their
 * boards have it (design review, brand-only footers) — except Mine oplysninger, which holds the
 * language control itself and keeps the mark centred (`.sitefoot__inner--centred`, at the end). */
@media (min-width: 48rem) {
    .sitefoot__inner {
        display: grid;
        grid-template-columns: 1fr auto 1fr;
    }

    .sitefoot__inner > .page__footer-brand {
        grid-column: 1;
        justify-self: start;
    }

    .sitefoot__inner > .page__operator {
        grid-column: 2;
    }

    .sitefoot__inner > .language {
        grid-column: 3;
        justify-self: end;
    }

    .sitefoot__inner:not(:has(> .language)) > .page__operator {
        grid-column: 3;
        justify-self: end;
    }
}

/* --- Support: people and teams in one list (2026-09-25 00:40) ---------------------------------- */

.supportfilter {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* The shared filter control on a <button>: the element's own font and pointer. */
.supportfilter .filters__choice {
    font-family: inherit;
    cursor: pointer;
}

.supportlist__type {
    width: 56px;
}

.supportlist__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-pill);
    background: var(--colour-surface-field);
    color: var(--colour-primary);
}

.supportlist__main,
.supportlist__sub {
    display: block;
}

.supportlist__sub {
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.supportlist__go {
    width: 32px;
    color: var(--colour-text-muted);
    text-align: right;
}

.selectedcard__note {
    margin: 4px 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    text-align: center;
}

/* --- Support: one panel for a person or a team, and the sort (2026-09-25 00:50) ---------------- */

/* "Have they ever signed in", under the chips, in the panel's quiet type. */
.selectedcard__state {
    margin: 4px 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* "Team" above a team's name, so the operator knows which kind of case landed. */
.selectedcard__kind {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-code);
    text-transform: uppercase;
}

.selectedcard__initials--team svg {
    display: block;
}

/* AN ACTION THAT NEEDS A REASON OPENS ITS FORM UNDER ITSELF. The summary is the button; the
 * browser's disclosure triangle is dropped because the button already says what it does. */
.panelaction > summary {
    list-style: none;
    cursor: pointer;
}

.panelaction > summary::-webkit-details-marker {
    display: none;
}

.panelaction__form {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    margin-top: var(--space-sm);
    padding: var(--space-sm);
    border-radius: 16px;
    background: var(--colour-surface-field);
}

.panelaction__lede {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* Members, invitations: a name or an address, and a word beside it. Long addresses wrap. */
.panellist {
    margin: 0;
    padding: 0;
    list-style: none;
}

.panellist__row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px var(--space-2xs);
    padding: var(--space-2xs) 0;
    border-bottom: var(--border-width) solid var(--colour-rule-warm-soft);
}

.panellist__main {
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
}

.panellist__sub {
    flex: 1 0 100%;
    order: 3;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    overflow-wrap: anywhere;
}

.panellist__aside {
    flex: 0 0 auto;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* THE SORT, WITH ITS OWN BUTTON (WCAG 3.2.2): a select that reloads the page on change moves a
 * keyboard user without asking. */
.supportsort {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2xs);
    margin-left: auto;
}

.supportsort__label {
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.supportsort__select {
    width: auto;
    min-width: 10rem;
}

.impersonation__tag {
    display: block;
}

/* The five columns of the combined list replace the old three; its cells wrap rather than clip. */
.supporttable .supportlist th:nth-child(1),
.supporttable .supportlist td:nth-child(1) {
    width: 52px;
}

.supporttable .supportlist th:nth-child(2),
.supporttable .supportlist td:nth-child(2) {
    width: 34%;
}

.supporttable .supportlist th:nth-child(3),
.supporttable .supportlist td:nth-child(3) {
    width: auto;
}

.supporttable .supportlist th:nth-child(4),
.supporttable .supportlist td:nth-child(4) {
    width: 150px;
}

.supporttable .supportlist td {
    padding-right: 12px;
}

.supporttable .supportlist th:nth-child(5),
.supporttable .supportlist td:nth-child(5) {
    width: 28px;
}

.supporttable .supportlist td:not(:first-child):not(:last-child) {
    overflow: visible;
    white-space: normal;
    overflow-wrap: break-word;
}

/* Design MINOR: the whole row is the target, so the chevron opens what it points at. */
.supportlist tr {
    position: relative;
}

.supportlist .supporttable__pick::after {
    content: '';
    position: absolute;
    inset: 0;
}

/* WHERE THE LIST IS NARROW, a row is a small card: the icon, the name and the way in, then its
 * facts beneath. Narrow is the list's own width, not the window's: on a phone, and equally at
 * 1024-1279 where the record takes 470px beside it and five table columns broke "Intet hold
 * endnu" one word to a line and cut every name to its first letters. */
.supporttable {
    container: supportlist / inline-size;
}

@container supportlist (max-width: 35.999rem) {
    .supporttable .supportlist,
    .supporttable .supportlist tbody {
        display: block;
    }

    .supporttable .supportlist thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
    }

    .supporttable .supportlist tr {
        display: grid;
        grid-template-columns: 48px minmax(0, 1fr) 24px;
        gap: 4px 12px;
        padding: 12px 0;
        border-bottom: var(--border-width) solid var(--colour-surface-field);
    }

    .supporttable .supportlist td {
        display: block;
        width: auto;
        padding: 0;
        border: 0;
    }

    .supporttable .supportlist td:nth-child(1) {
        grid-row: 1 / span 3;
        width: auto;
    }

    .supporttable .supportlist td:nth-child(2),
    .supporttable .supportlist td:nth-child(3),
    .supporttable .supportlist td:nth-child(4) {
        grid-column: 2;
        width: auto;
    }

    .supporttable .supportlist td:nth-child(5) {
        grid-column: 3;
        grid-row: 1;
        width: auto;
    }
}

/* Administratorer: the address under the name, on its own line; a role's description under its
 * name; a long title hyphenated rather than broken anywhere. */
.adminlist__email,
.adminlist__hint {
    display: block;
}

.adminlist__heading {
    overflow-wrap: normal;
    hyphens: auto;
}

/* --- Best Team Name, judged by a person (2026-09-25 06:40) ------------------------------------- */

/* The list as text: wide enough to read, never wider than the card. */
.shortlistcopy__text {
    width: 100%;
    font-family: inherit;
    resize: vertical;
}

.shortlistcopy__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-xs);
    margin: var(--space-xs) 0 0;
}

.shortlistcopy__status {
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* One checkbox per name, in columns where there is room. A name is participant text and can be
 * one long compound, so it wraps anywhere rather than widening the page. */
.shortlistpick {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
    gap: 0 var(--space-md);
}

.shortlistpick__name {
    min-width: 0;
    overflow-wrap: anywhere;
}

/* --- The shared footer and the landing's phone gutters (advisor, 2026-09-25 03:00) -------------
 * The footer partial is used by the gate family (/, /sign-in, /check-email …) and by /materials,
 * but its layout lived only in public.css, which the gate layout does not load: on the first
 * screens a tester sees, the footer had no grid, no gap and no gutter. Its layout is here now;
 * its colours stay where they are (the ink footer above, and public.css for /materials).
 */
.publicfoot__inner {
    display: grid;
    gap: var(--space-sm);
    margin-inline: auto;
    padding-top: var(--space-lg);
    padding-bottom: var(--space-lg);
}

/* ON THE INK FOOTER, INK-SAFE CONTROLS. The global focus ring is True Blue, which is invisible on
 * this True Blue ground, and a .link-button (sign out, on the onboarding screens) is True Blue
 * text. Both answers lived only in public.css, which the gate screens do not load. */
.publicfoot :focus-visible {
    outline-color: var(--colour-text-inverse);
}

.publicfoot .link-button {
    color: var(--colour-text-inverse);
}

.publicfoot__operator {
    margin: 0;
    max-width: 60ch;
    font-size: var(--font-size-sm);
}

/* GUTTERS BELOW 80rem. These three had padding-inline only from 80rem, so below it their text ran
 * to the screen's edge. A max-width query, not a base rule, so the board's wider gutters from
 * 80rem (above) keep winning. 18px is the bar's own phone gutter, so the wordmark, the bands and
 * the footer share one left edge. */
@media (max-width: 79.99rem) {
    .publicfoot__inner {
        padding-inline: 18px;
    }
}

/* THE LONGER NAME, WHERE IT DOES NOT FIT WITH ITS TRACKING (N, 2026-09-24).
 *
 * "NOVO STEP CHALLENGE" is nine letters longer than the mark it replaced, and at the boards'
 * 0.18em it did not fit two bars. Measured with the captain's session and as a guest:
 * - the signed-in bar from 64rem to 80rem, where the mark shares the row with the destinations
 *   and the sign-out: at 1024 the sign-out ended at 1053 in a 1009 viewport; untracked it ends
 *   inside. Below 64rem the bar holds the mark and the menu only, and the tracked mark fits.
 * - the guest bar below 24rem, where the mark broke onto two lines at 320 (53px tall); untracked
 *   it is one line of 228px. From 390 the tracked mark fits in both bars and keeps the boards'
 *   0.18em.
 * Last in the sheet because four earlier rules set this property on these selectors. */
@media (min-width: 64rem) and (max-width: 79.9375rem) {
    .appbar .gatemark {
        letter-spacing: 0;
    }
}

@media (max-width: 23.99rem) {
    .gatebar--shared .gatemark {
        letter-spacing: 0;
    }
}

/* === FOUNDATION 2026 ============================================================================
 * The shared layer of the 2026 boards (docs/design/locked/boards/Foundations.dc.html, canvas
 * version 17; design brief of 2026-09-25, "Order and split" 1): the bars, the footers with the
 * novohealth wordmark, chips, fields and the footprints. No screen layout - each screen group
 * lays its own screens out on top of this. Colours come from tokens.css (Novo's 2026 CVI).
 *
 * Last in the sheet, and every selector below restates the one it replaces (see the cascade
 * notes above: an earlier `.adminshell .adminfoot` is not beaten by a later `.adminfoot`).
 */

/* --- The bars: 72px on a tablet and a desktop, 58 on a phone -------------------------------- */
@media (min-width: 48rem) {
    /* 71 + the bar's 1px rule = the board's 72. The row inside it carried the old 84 too. */
    .appbar__inner,
    .appbar .topbar {
        min-height: 71px;
    }

    .gatebar--shared,
    .gatebar--shared .gatebar__inner {
        min-height: 72px;
    }
}

@media (max-width: 47.9375rem) {
    /* THE PHONE BAR IS 58, ONE ROW, ITS CONTROLS CENTRED IN IT. The height sits on the row, not
     * on the block-level bar around it, so align-items can centre the 48px targets (5px above
     * and below); on the outer bar the row sat at the top with the spare height beneath it. The
     * bar's own floor (88 from the older desktop rule) is released so the row alone sets it. */
    .gatebar--shared {
        min-height: 0;
    }

    .gatebar--shared .gatebar__inner {
        min-height: 58px;
        align-items: center;
    }

    /* THE ROW FITS AT 390, THE PHONE BOARD'S WIDTH, by taking MobileFamily's own figures: the
     * bar's 16px gutter (.m-bar), and the pill's 14px segments 2px apart (.ph-bar-guest .seg).
     * With 18, 16 and 4 the tracked wordmark (236px from 24rem) and the 114px pill needed 358px
     * of a 354px row, so the bar wrapped to 114px at 390. Now the pill is 104 and the row 358:
     * 10px to spare at 390, 4 at 384 where the tracking starts. Below that the wordmark is
     * untracked (188px) and fits down to about 332; at 320 the row wraps, which is reflow, not loss. */
    .gatebar--shared .gatebar__inner {
        padding-inline: 16px;
    }

    .gatebar--shared .language__options {
        gap: 2px;
    }

    .gatebar--shared .language__current,
    .gatebar--shared .language__choice {
        padding-inline: 14px;
    }

    /* 14px, one step under the board's 15 (.p-mark): at 15 the tracked mark is 253px and the row
     * no longer fits at 390 beside a pill that keeps the 48px targets Foundations asks of a
     * phone. */
    .gatebar--shared .gatemark {
        font-size: 14px;
    }
}

@media (min-width: 80rem) {
    .appbar .whoami__initials {
        width: 32px;
        height: 32px;
    }

    .adminshell .adminbar,
    .adminshell .adminbar__inner {
        min-height: 72px;
    }

    /* 55 + the row's 1px rule = 56. */
    .adminsub__inner {
        min-height: 55px;
    }
}

/* The person at 1440 used to be the role chip, the name and Sign out, with no initials. Since the
 * way to the participant pages joined the bar (option A, 2026-09-27) the initials are drawn at every
 * width and the name is not — admin.css, "THE BAR MAKES ROOM". */

/* The mark, as .a-mark: the product name on one line at 15px, the section word 11px, stacked
 * under it where the pair does not fit beside the menu (the board's container rule). */
@media (min-width: 80rem) {
    .adminshell .adminbar__product {
        font-size: 15px;
        white-space: nowrap;
    }

    .adminshell .adminbar__section {
        font-size: 11px;
    }
}

@media (min-width: 80rem) and (max-width: 89.9375rem) {
    .adminshell .adminbar__mark {
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
    }
}

/* The guest footer on the guest bar's 96px gutter (.g-foot) from 1440, where the board draws it;
 * at 1280 that gutter would push the row onto two lines, so it keeps 64 there. This is the gate
 * layout's footer only: on /materials public.css (loaded later) keeps its own column, an open
 * decision recorded there against GuestMaterials. */
@media (min-width: 90rem) {
    .publicfoot__inner {
        padding-inline: 96px;
    }
}

/* The second level's current page: a 44px tinted block with a 12px corner, not a pill - the pill
 * is the first level's shape, and two rows of pills read as one menu. */
.adminsub__link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    border-radius: 12px;
}

/* --- The footers: one 72px ink row with the name and the novohealth mark ------------------------- */
.footmark {
    display: block;
    width: 158px;
    height: 24px;
    flex-shrink: 0;
}

/* 20px tall on a phone (locked-design-system.md §10; MobileFamily draws it so), its width
 * following the file's own proportion (about 132) so the supplied mark is never stretched. */
@media (max-width: 47.9375rem) {
    .footmark {
        width: auto;
        height: 20px;
    }
}

.page__operator,
.publicfoot__operator {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 24px;
}

/* THE FOOTER'S WORDS ARE THE QUIET ON-INK VOICE, #C9D6F0, as the boards set them (.p-foot-mid,
 * .p-foot-lang). They took the Light Blue accent before, and the 2026 CVI turned that accent
 * into Now Turquoise, which the boards keep for eyebrows and section words - not for a sentence. */
.sitefoot .page__operator,
.sitefoot .language,
.adminshell .adminfoot .language,
.sitefoot .language__label,
.adminshell .adminfoot .language__label,
.publicfoot p {
    color: var(--colour-text-on-primary-muted);
}

/* The wordmark stays white: `.publicfoot p` above would otherwise reach it too. */
.publicfoot .publicfoot__brand {
    color: var(--colour-text-inverse);
}

/* One row at a desktop: the novohealth mark on one line, and the
 * participant footer on the bar's own edges (90rem, 64px gutters) rather than the narrower page
 * column, which squeezed the name and the language onto two lines each. */
@media (min-width: 80rem) {
    .sitefoot__inner {
        max-width: 90rem;
        padding-inline: 64px;
    }

    .sitefoot__inner > .page__footer-brand,
    .sitefoot .language {
        white-space: nowrap;
        flex-wrap: nowrap;
    }

    .page__operator,
    .publicfoot__operator {
        flex-wrap: nowrap;
        max-width: none;
        white-space: nowrap;
    }
}

@media (min-width: 48rem) {
    .sitefoot {
        padding-block: 0;
    }

    /* 72 when it is one row; 12px above and below when it wraps, so a wrapped footer does not
     * press its rows against the edges of the band. */
    .sitefoot__inner {
        min-height: 72px;
        align-items: center;
        padding-block: 12px;
    }
}

@media (min-width: 64rem) {
    .publicfoot__inner {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        justify-content: space-between;
        gap: 12px 32px;
        min-height: 72px;
        padding-block: 12px;
    }

    .publicfoot__brand,
    .publicfoot__operator {
        margin: 0;
    }
}

@media (min-width: 80rem) {
    .adminshell .adminfoot {
        min-height: 72px;
    }
}

/* --- One chip: filled, never outlined, a 12px bold word in sentence case --------------------- */
.chip {
    gap: 6px;
    padding: 5px 10px;
    font-size: 12px;
    letter-spacing: 0;
}

/* --- One field: 52px, a 12px corner, the neutral 1px edge (the screen's own field is 2px ink
 * where a board draws it so). The type stays 16px, one pixel over the board's 15: under 16px a
 * phone browser zooms the page when the field takes focus. */
/* Item 12: 48 everywhere, desktop and phone (the component sheet; it was 52 on a desktop). */
.field__input,
.field__select {
    height: var(--control-height);
    border-radius: var(--control-radius);
}

/* --- The footprints: the page head's mark, 96px on a desktop, 56 on a phone. Nothing places it
 * yet: each screen group puts partials/footprints in its page heads. */
.prints {
    display: block;
    flex-shrink: 0;
    width: 96px;
    height: 96px;
}

@media (max-width: 47.9375rem) {
    .prints {
        width: 56px;
        height: 56px;
    }
}

/* EVERY CARD IS 20px ROUND. Every 2026 board draws one card (.p-card, and .m-card on a phone) and
 * one ink panel (.p-ink), all at 20px; the product's card classes still carried the 24-32px of the
 * boards they were built from, one value per screen. Each selector below repeats the one that set
 * its radius, so it wins at equal specificity by coming last - at every width, since those rules
 * sit in and out of media queries alike. The radius only: a card's padding is part of its screen's
 * layout, and each screen group sets it (24px on the boards) when it lays that screen out.
 * The converter is not here: its row has its own brief (docs/task-briefs/the-converter-looks-finished.md). */
.panel,
.roster-panel,
.board-panel,
.details-panel,
.competition,
.gatecard,
.gate,
.message,
.inkpanel,
.datepanel,
.adcard,
.supportsearch,
.supporttable,
.selectedcard,
.confirm,
.noteam,
.decision,
.summarycard,
.maillist,
.matindex,
.matblock,
.adminshell .admin__form,
.adminshell .admin__section,
.card,
.adminshell .card,
.adminshell .support > form,
.adminshell .support > .support__scroller,
.adminshell .support > .support__section {
    border-radius: var(--radius-2xl);
}

/* A FIELD'S LABEL IS 13px BOLD, as every board's .fld-label draws it (it was 14). The base classes
 * only: a screen that sizes its own labels keeps its more specific rule, and the 6px between a
 * label and its field is left to each form's own layout. */
.gate__label,
.field__label {
    font-size: 13px;
    font-weight: var(--font-weight-bold);
}

/* Sixteen between a page's sections, as every participant board spaces them (.p-main's gap). */
.pagestack {
    gap: 16px;
}

/* --- The participant page's own inset: 24 above the title and 40 above the footer, the .p-main
 * every participant board draws (the error layout shares the shell and takes the same). */
@media (min-width: 48rem) {
    .page {
        padding-block: 24px 40px;
    }
}

/* Mine skridt's own phone spacing (10px sections, 4px under the bar) went on 2026-10-06: the shared
 * page head starts and spaces every participant tab alike, so a tab switch moves nothing. */

/* --- The participant bar at the narrowest phones: the wordmark untracked below 24rem, as the guest
 * bar's already is. Tracked, it is 236px; with the 32px gap and the avatar that is 300px of a 284px
 * row at 320, and the avatar wrapped onto a second line under the wordmark. */
@media (max-width: 23.99rem) {
    .appbar .gatemark {
        letter-spacing: 0;
    }
}

/* The aside is the board's 400 and the track is too, so the right column ends on the content
 * edge with the strip and the head above it (design review D2.1: it stopped 20-40px short when
 * the card was 400 inside a wider track). */
@media (min-width: 64rem) {
    .teamwork {
        grid-template-columns: minmax(0, 1fr) 400px;
        gap: 16px;
    }

    .teamwork__aside {
        width: auto;
    }
}

.roster-panel.panel,
.teamwork .panel {
    padding: 24px;
}

.roster-panel .panel__title,
.roster-invites__title {
    font-size: 20px;
    line-height: 1.2;
    letter-spacing: -0.015em;
}

/* THE TABLE'S OWN ROWS FROM 1280, where the roster is one line per person. Below that each row
 * is two lines by the product's own decision (touch targets), and keeps its rules. */
@media (min-width: 80rem) {
    /* The table's labels sit on a rule, with no band behind them. */
    .roster-panel .roster-table:not(.roster-table--invites) th {
        padding: 0 8px 10px;
        border-bottom: 1px solid var(--colour-rule-warm);
        background: none;
        color: var(--colour-text-muted);
        font-size: 11px;
        font-weight: var(--font-weight-bold);
        letter-spacing: 0.14em;
        text-transform: uppercase;
    }

    .roster-panel .roster-table:not(.roster-table--invites) td {
        height: 60px;
        padding: 8px;
        border-bottom: 1px solid var(--colour-rule-warm-soft);
        background: none;
    }

    .roster-panel .roster-table:not(.roster-table--invites) tr:last-child td {
        border-bottom: 0;
    }

    /* The reader's own row: the tint, rounded at its two ends. */
    .roster-panel .roster-table__row--you td {
        background: var(--colour-surface-field);
        border-bottom-color: transparent;
    }

    .roster-panel .roster-table__row--you td:first-child {
        border-radius: 14px 0 0 14px;
    }

    .roster-panel .roster-table__row--you td:last-child {
        border-radius: 0 14px 14px 0;
    }
}

/* THE INVITATIONS ARE A TABLE ONLY FROM 1408. Between 1280 and that the product stacks each
 * invitation as a small card so its actions do not wrap (F-038), and a row's rules would land on
 * every stacked cell — the must-not-repeat list's "Slet hung underneath" at 1280. */
@media (min-width: 88rem) {
    .roster-panel .roster-table--invites th {
        padding: 0 8px 10px;
        border-bottom: 1px solid var(--colour-rule-warm);
        background: none;
        color: var(--colour-text-muted);
        font-size: 11px;
        font-weight: var(--font-weight-bold);
        letter-spacing: 0.14em;
        text-transform: uppercase;
    }

    .roster-panel .roster-table--invites td {
        height: 60px;
        padding: 8px;
        border-bottom: 1px solid var(--colour-rule-warm-soft);
        background: none;
    }

    .roster-panel .roster-table--invites tr:last-child td {
        border-bottom: 0;
    }
}

/* Remove and Delete are text links: underlined, the size of the row's words. The reminder and
 * "invite again" beside Delete stay the outlined pill the board draws. */
.roster-panel .roster-table__action--text {
    padding: 0 6px;
    color: var(--colour-text);
    font-size: 14px;
    font-weight: var(--font-weight-bold);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* --- The captain's handover (CaptainActions.dc.html): each member a bordered row, as the board
 * draws its choices. They stay links — choosing opens the confirmation that names the person — so
 * nothing here pretends to be a radio button. */
.handover {
    display: flex;
    flex-direction: column;
    gap: 6px;
    border-top: 0;
}

.handover .handover__item {
    border: 0;
}

.handover .handover__choice {
    display: flex;
    align-items: center;
    min-height: 48px;
    padding: 0 14px;
    border: 1px solid var(--colour-border-field);
    border-radius: 12px;
    background: var(--colour-surface);
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    text-decoration: none;
}

.handover .handover__choice:hover {
    border-color: var(--colour-primary);
    background: var(--colour-surface-field);
}

/* --- A captain's confirmation (CaptainActions.dc.html): the act and the way back on one row. */
@media (min-width: 48rem) {
    div.decision__actions {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 8px;
    }

    div.decision__actions > form {
        margin: 0;
    }
}

/* --- Stilling (Standings.dc.html, 2026) -------------------------------------------------------
 * The heading as the other participant pages' (the campaign day as the eyebrow), four figure
 * cards — the reader's place on ink — then the scope as one segmented choice on its own row, and
 * the board beneath. The file draws both views side by side because it is a specification; the
 * page shows one at a time, full width. */

.summarycards {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
}

/* AS MANY EQUAL COLUMNS AS THERE ARE CARDS (advisor sweep 1): a team that is not ranked has three,
 * and a fixed four left an empty slot at the right edge. From 80rem the row fills the width with
 * however many there are; below it the two-column rule further down still holds. */
@media (min-width: 80rem) {
    .summarycards {
        grid-template-columns: none;
        grid-auto-flow: column;
        grid-auto-columns: minmax(0, 1fr);
    }
}

.summarycards .summarycard {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 22px 24px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: var(--radius-2xl);
    background: var(--colour-surface);
    color: var(--colour-text);
}

.summarycards .summarycard--you {
    border-color: var(--colour-primary);
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
}

.summarycards .summarycard__pair,
.summarycards .summarycard__value {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    border: 0;
}

.summarycards .summarycard__eyebrow {
    color: var(--colour-text-muted);
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
}

.summarycards .summarycard--you .summarycard__eyebrow {
    color: var(--colour-accent-on-primary);
}

.summarycards .summarycard__figure {
    margin-top: 8px;
    font-size: 40px;
    font-weight: var(--font-weight-bold);
    line-height: 1;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
}

.summarycards .summarycard__figure--words {
    font-size: 22px;
    line-height: 1.15;
    letter-spacing: -0.01em;
}

.summarycards .summarycard__sub {
    margin-top: 6px;
    color: var(--colour-text-muted);
    font-size: 13px;
}

.summarycards .summarycard--you .summarycard__sub {
    color: var(--colour-text-on-primary-muted);
}

/* The scope: "Vis", then one segmented choice. Its steps basis follows on the same row. */
.filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 24px;
}

.filters .filters__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin: 0;
}

.filters .filters__prefix {
    color: var(--colour-text-muted);
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
}

/* THE ONE TOGGLE SYSTEM: a tint trough, 44px segments, the pressed one ink. The two board tabs
 * and the scope are drawn the same way, as the board draws every choice of one. */
.boardtabs,
.filters__segments {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 2px;
    padding: 4px;
    border: 0;
    border-radius: var(--radius-pill);
    background: var(--colour-surface-field);
}

.boardtabs .boardtabs__tab,
.filters .filters__choice:not(.filters__choice--quiet) {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 18px;
    border: 0;
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--colour-text-muted);
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
    text-decoration: none;
}

.boardtabs .boardtabs__tab--on,
.filters .filters__choice--on:not(.filters__choice--quiet) {
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
    font-weight: var(--font-weight-bold);
}

@media (max-width: 79.9375rem) {
    .summarycards {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* Three cards in two columns leave an empty cell: the lone last card spans the row
     * (design review of sweep 1), as the Mine skridt tiles already do. */
    .summarycards > :last-child:nth-child(odd) {
        grid-column: 1 / -1;
    }
}

@media (max-width: 47.9375rem) {
    .summarycards {
        gap: 10px;
    }

    .summarycards .summarycard {
        padding: 14px 16px;
    }

    .summarycards .summarycard__figure {
        font-size: 28px;
    }
}

/* Stilling, continued: the cards read from their left edge; the scope row starts at the page's. */
.summarycards .summarycard,
.summarycards .summarycard__pair,
.summarycards .summarycard__value {
    align-items: flex-start;
    text-align: left;
}

.pagestack > .filters {
    flex-direction: row;
    justify-content: flex-start;
    margin: 0;
    padding: 0;
}

.pagestack > .filters .filters__row--secondary {
    margin: 0;
}

@media (min-width: 48rem) {
    .pagestack > .board-panel {
        padding: 24px;
    }

    .pagestack > .filters .filters__row--secondary {
        flex-basis: auto;
        width: auto;
    }
}

/* Stilling on a phone: where the scope's three choices wrap, the trough is a rounded box rather
 * than a pill; and at the narrowest phones the four figures take one card per row. */
@media (max-width: 47.9375rem) {
    .filters__segments,
    .boardtabs {
        border-radius: 24px;
    }
}

@media (max-width: 23.99rem) {
    .summarycards {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* THE PAGE IS THE WINDOW'S WIDTH, NOT ITS CONTENT'S. The body centres the shell in a flex column,
 * so `.page` was sized to fit its content — and fit-content never goes below the content's minimum,
 * which on Stilling at 320 is the standings table plus two paddings: 343px, a page that scrolled
 * sideways before the table's own scroll container got the chance to. Stated as the full width
 * (still capped by its max-width), the table scrolls inside its panel, which is what it is for. */
.page {
    width: 100%;
}

.pagestack > * {
    min-width: 0;
}

/* --- Konkurrencer (Competitions.dc.html, 2026) ------------------------------------------------
 * The heading with the reader's team as one compact row beside the footprints; four cards, each
 * an icon tile and its state on the top line, then the name, the rule and its facts as tint
 * boxes; the diploma as a status row. */

.competition-list {
    gap: 16px;
}

.competition-list .competition {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
        'icon meta'
        'body body';
    align-content: start;
    gap: 12px;
    height: 100%;
    padding: 24px;
}

.competition__icon {
    grid-area: icon;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 12px;
    background: var(--board-tile);
}

.competition__icon svg {
    width: 22px;
    height: 22px;
    fill: none;
    stroke: var(--colour-primary);
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.competition-list .competition__meta {
    grid-area: meta;
    justify-self: end;
    align-self: center;
    margin: 0;
}

.competition-list .competition__body {
    grid-area: body;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.competition-list .competition__name {
    margin: 0;
    font-size: 20px;
    line-height: 1.2;
    letter-spacing: -0.015em;
}

.competition-list .competition__rule {
    margin: 0;
}

/* Each fact a tint box: the figure over what it means. Directly under the card's words, with the
 * body's own gap above them — not pushed to the card's floor by an auto margin (copilot-210). */
.competition-list .competition__facts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    margin: 0;
    padding: 0;
    border: 0;
}

.competition-list .competition__fact {
    margin: 0;
    padding: 12px 14px;
    border: 0;
    border-radius: 14px;
    background: var(--colour-surface-field);
}

.competition-list .competition__fact-label {
    font-size: 16px;
    font-weight: var(--font-weight-bold);
}

.competition-list .competition__fact-detail {
    margin: 2px 0 0;
    color: var(--colour-text-muted);
    font-size: 13px;
}

@media (max-width: 47.9375rem) {
    .competition-list .competition {
        padding: 16px;
    }
}

.competition-list .competition__meta {
    display: flex;
    justify-content: flex-end;
    width: 100%;
}
/* A diploma that is not ready yet is a state, not a card: the board's status row, its edge the
 * quiet one (nothing has gone wrong; the result is simply not out). */
.panel.panel--state {
    padding: 14px 18px;
    border: 1px solid var(--colour-rule-warm);
    border-left: 4px solid var(--colour-border-field);
    border-radius: 0 14px 14px 0;
}

/* The aside is the board's 400 and the track is too, so the right column ends on the content
 * edge with the strip and the head above it (design review D2.1: it stopped 20-40px short when
 * the card was 400 inside a wider track). */
@media (min-width: 64rem) {
    .profilework {
        grid-template-columns: minmax(0, 1fr) 400px;
        gap: 16px;
    }

    .profilework__aside {
        width: auto;
    }
}

.profilework .panel {
    padding: 24px;
}

.profileform > .field + .field,
.details-panel .profileform__language {
    margin-top: 18px;
    padding-top: 18px;
    border-top: 1px solid var(--colour-rule-warm-soft);
}

.details-panel .gate__hint {
    font-size: 13px;
}

.details-panel .profileform__language-label {
    font-size: 13px;
    font-weight: var(--font-weight-bold);
}

.details-panel > .button--wide {
    width: auto;
    margin-top: 18px;
}

.emailcard .emailcard__value {
    font-size: 18px;
    font-weight: var(--font-weight-bold);
    overflow-wrap: anywhere;
}

/* What is stored: ruled rows, not bullets. */
.storedcard .storedcard__list {
    margin: 8px 0 0;
    padding: 0;
    list-style: none;
}

.storedcard .storedcard__list li {
    padding: 8px 0;
    border-bottom: 1px solid var(--colour-rule-warm-soft);
    font-size: 14px;
}

.storedcard .storedcard__list li::before {
    content: none;
}

.profilework .teamcard .teamcard__name {
    margin-top: 4px;
    font-size: 18px;
    line-height: 1.2;
    letter-spacing: -0.01em;
}

/* --- The must-not-repeat list (docs/task-briefs/the-2026-design-must-not-repeat.md) ----------
 * /team at 375: a label that wraps must not drop its figure below the others — each item fills
 * its row and sets the figure at its foot, so the three stand on one line. */
@media (max-width: 47.9375rem) {
    /* /standings at 375: the scope's three choices wrap as a tidy pair and a full row, not
     * raggedly; each segment fills its cell. */
    .filters__segments {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .filters__segments > :last-child:nth-child(odd) {
        grid-column: 1 / -1;
    }

    .filters .filters__segments .filters__choice {
        justify-content: center;
        text-align: center;
    }
}

@media (max-width: 47.9375rem) {
    .filters .filters__segments .filters__choice {
        padding: 0 10px;
        white-space: nowrap;
    }
}

/* The aside is the board's 400 and the track is too, so the right column ends on the content
 * edge with the strip and the head above it (design review D2.1: it stopped 20-40px short when
 * the card was 400 inside a wider track). */
@media (min-width: 64rem) {
    .helpgrid {
        grid-template-columns: minmax(0, 1fr) 400px;
        gap: 16px;
    }

    /* ITS OWN TRACK IS THE 400 TOO. The aside is a grid, and its implicit column grew to the
     * dates panel's longest line, so every card in it ran 35px past the content edge (the last
     * participant pass, measured at 1440: 435px cards in a 400px column). */
    .helpgrid__aside {
        width: auto;
        grid-template-columns: minmax(0, 1fr);
    }
}

.helpgrid .panel,
.helpgrid .inkpanel,
.helpgrid .datepanel {
    padding: 24px;
}

/* --- The design review of the participant group --------------------------------------------- */

/* The participant footer between 1024 and 1279, as TabletSteps.dc.html (1024) draws it: one 72px
 * row — the wordmark on one line, the novohealth mark, and the language's word inline with its
 * choices. It stacked all three and stood 99px tall at 1024. Narrower than 1024 the footer keeps
 * its stacked form. */
@media (min-width: 64rem) and (max-width: 79.9375rem) {
    .sitefoot .page__footer-brand {
        white-space: nowrap;
    }

    .sitefoot .page__operator {
        flex-wrap: nowrap;
    }

    .sitefoot .language {
        display: flex;
        flex-wrap: nowrap;
        align-items: center;
        gap: 12px;
    }
}

/* ==== DESIGN 2026 — THE GUEST GROUP ================================================================
 * The landing, sign-in family, onboarding and materials screens laid out as their 2026 boards draw
 * them (docs/design/locked/boards: Main, PreStart, GuestAuth, GuestOnboarding, GuestMaterials;
 * MobileFamily for the phone). On top of Foundation's tokens, bars, footers, buttons and fields.
 * Every figure measured on a 1440 board sits inside the canvas's own media query. */

@media (min-width: 64rem) {
    .gateshell--landing .gatemain--split .gatemain__inner {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 480px);
        align-items: start;
        gap: 48px;
        min-height: 0;
        max-width: none;
        padding: 24px 64px 0;
    }

    .gatecard--landing {
        display: block;
        max-width: none;
        margin: 0;
        padding: 24px 0 0;
        border: 0;
        border-radius: 0;
        background: none;
        box-shadow: none;
    }
}

@media (min-width: 80rem) {
    .gateshell--landing .gatemain--split .gatemain__inner {
        grid-template-columns: minmax(0, 1fr) 544px;
        gap: 64px;
        padding: 24px 96px 0;
    }
}

.gatecard--landing .gatecard__eyebrow {
    font-size: 12px;
    letter-spacing: 0.18em;
}

/* At the specificity of the landing's earlier `.gateshell--landing .gatecard__head h1`, which an
 * element-qualified selector wins over a bare class however late the class comes. */
.gateshell--landing .gatecard__head h1 {
    margin-top: 16px;
    font-size: clamp(2.5rem, 1rem + 4vw, 4.5rem);
    line-height: 0.98;
    letter-spacing: -0.035em;
}

.gatecard--landing .gatecard__lede {
    margin-top: 20px;
    max-width: 580px;
    font-size: 19px;
    line-height: 1.5;
}

.gatecard--landing .gate__form {
    margin-top: 32px;
    max-width: 560px;
}

.gatecard--landing .gate__label {
    margin-bottom: 8px;
    font-size: 14px;
}

.gatecard--landing .gate__hint {
    margin-top: 10px;
    font-size: 14px;
}

/* The facts: one row above a rule, no hairlines between (the board's .lp-facts). */
.gatecard--landing .gatecard__steps {
    display: flex;
    flex-wrap: wrap;
    gap: 10px 24px;
    margin: 28px 0 0;
    padding: 20px 0 0;
    border-top: 1px solid var(--board-rule);
    list-style: none;
}

.gatecard--landing .gatecard__steps li {
    padding: 0;
    font-size: 14px;
    font-weight: var(--font-weight-bold);
}

.gatecard--landing .gatecard__steps li + li::before,
.gatecard--landing .gatecard__steps li:not(:last-child)::after {
    content: none;
}

/* --- The landing on a phone (MobileFamily.dc.html's first frame) -----------------------------------
 * The heading on the ground with the footprints beside it, the form alone in a white card, and the
 * pulse as one short card: the day, the total and the two counts. */
.landing__prints-phone {
    display: none;
}

@media (max-width: 47.9375rem) {
    .gatecard--landing {
        margin: 0;
        padding: 16px 18px 0;
        border: 0;
        border-radius: 0;
        background: none;
        box-shadow: none;
    }

    .gatecard--landing .gatecard__head {
        position: relative;
        padding-right: 64px;
    }

    .landing__prints-phone {
        display: block;
        position: absolute;
        top: 0;
        right: 0;
    }

    .gatecard--landing .gatecard__eyebrow {
        display: none;
    }

    .gateshell--landing .gatemain__inner {
        padding-inline: 0;
    }

    /* The board's phone frame starts the heading just under the bar and puts "Three steps" 32px
     * under the pulse card; the gate shell's 64px above and below is the desktop's. */
    .gateshell--landing .gatemain {
        padding-top: 8px;
        padding-bottom: 0;
    }

    /* MobileFamily draws no facts row: team size is in "Three steps" and every location is not a
     * phone reader's question. The sign-up deadline stays when there is one, because nothing else on
     * the page states it (see the view); the start date goes, as the lede and the pulse state it. */
    .gatecard--landing .gatecard__steps > li:nth-child(-n + 2),
    .gatecard--landing .gatecard__steps:not(:has(> li:nth-child(3))),
    .gatecard--landing .gatecard__steps:has(> .gatecard__fact--start) {
        display: none;
    }

    .gateshell--landing .gatecard__head h1 {
        margin-top: 0;
        font-size: 26px;
        line-height: 1.1;
        letter-spacing: -0.02em;
    }

    .gatecard--landing .gatecard__lede {
        margin-top: 8px;
        font-size: 14px;
    }

    .gatecard--landing .gate__form {
        margin-top: 16px;
        padding: 16px;
        border: 1px solid var(--board-rule);
        border-radius: 20px;
        background: var(--colour-surface);
    }

    .gatecard--landing .gate__form > div.field:first-of-type {
        margin-top: 0;
    }

    /* The pulse card sits 12px under the form card, as MobileFamily stacks them. */
    .gateshell--landing .gatemain__inner {
        row-gap: 12px;
    }
}

/* --- The sign-in family (GuestAuth.dc.html) --------------------------------------------------------
 * The mail state's illustration tile: 48px, the 2026 boards' illustration tile (--board-tile), empty
 * until Novo's icon set arrives. The card, its heading, the 2px primary field and the 56px action are already the board's. */
.gatecard__icon {
    width: 48px;
    height: 48px;
    border-radius: 12px;
    background: var(--board-tile);
}

/* --- Onboarding (GuestOnboarding.dc.html) ----------------------------------------------------------
 * Create a team: "Where the team counts" under a hairline, its one line in quiet type, and Country
 * above EVP area at full width with ink labels, as the board stacks them. */
.placegroup {
    margin-top: 22px;
    padding-top: 18px;
    border-top: 1px solid var(--board-rule-inner);
}

.placegroup__note {
    margin: 2px 0 8px;
    font-size: 14px;
}

.placegroup__fields {
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
}

.placegroup__fields .gate__label {
    color: var(--colour-primary);
}

/* --- The sign-in family and onboarding: GuestAuth and GuestOnboarding ---------------------------------
 * Every card on those boards is 400 wide with 28 inside, its heading 28px, and it starts 48 under the
 * bar. /sign-in is its own page since design v4 (`main.frontpage`, the v4 sign-in layer at the end of
 * this file), so none of these reach it. */
.gateshell:not(.gateshell--landing) .gatemain {
    padding-top: 48px;
}

.gateshell .gatecard:not(.gatecard--landing) {
    max-width: 400px;
    padding: var(--card-padding);
}

.gateshell .gatecard:not(.gatecard--landing) .gatecard__head h1 {
    font-size: var(--font-size-gate-title-phone);
    line-height: 1.15;
    letter-spacing: -0.02em;
}

@media (min-width: 48rem) {
    .gateshell .gatecard:not(.gatecard--landing) .gatecard__head h1 {
        font-size: var(--font-size-gate-title);
    }
}

@media (max-width: 47.9375rem) {
    .gateshell:not(.gateshell--landing) .gatemain {
        padding-top: 8px;
    }

    .gateshell:not(.gateshell--landing) .gatemain__inner {
        padding-inline: 18px;
    }

    .gateshell .gatecard:not(.gatecard--landing) {
        max-width: none;
        padding: var(--card-padding-phone);
    }
}

/* --- The guest footer at 1280: one row on the bar's 96px gutter ------------------------------------
 * At 64 it still wrapped the links onto a second row (105px, the board draws 72). One row that
 * never wraps. */
@media (min-width: 80rem) {
    .publicfoot__inner {
        flex-wrap: nowrap;
        padding-inline: 96px;
    }

    .publicfoot__brand {
        flex: none;
        flex-wrap: nowrap;
        white-space: nowrap;
    }

    .publicfoot__operator {
        flex: 1 1 auto;
        flex-wrap: wrap;
        justify-content: flex-end;
        min-width: 0;
        white-space: normal;
        text-align: right;
    }
}

/* --- The error pages: the guest shell, as GuestMaterials' error states say ("same shell") ------------
 * The error layout keeps its own markup (no session, so no switcher or navigation: see
 * layouts/error); it takes the guest bar's ground, height and gutters, a footer spread like the
 * guest footer, and the board's error card: 24 inside, the heading at 18. */
.errorshell .appbar {
    border-bottom: 0;
    background: none;
}

@media (min-width: 48rem) {
    .errorshell .appbar .appbar__inner {
        min-height: 72px;
    }
}

@media (min-width: 64rem) {
    .errorshell .sitefoot .sitefoot__inner {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 32px;
    }
}

.errorshell .message {
    padding: 24px;
}

.errorshell .message__heading {
    font-size: 18px;
    letter-spacing: -0.01em;
}

@media (min-width: 80rem) {
    .errorshell .appbar .appbar__inner,
    .errorshell .sitefoot .sitefoot__inner {
        max-width: 90rem;
        margin-inline: auto;
        padding-inline: 96px;
    }
}

@media (max-width: 79.99rem) {
    .errorshell .appbar .appbar__inner,
    .errorshell .sitefoot .sitefoot__inner {
        padding-inline: 18px;
    }
}

/* The error page's one way out, full width on a phone so "Back to Novo Step Challenge" (and the
 * Danish "Tilbage til …") stays one line. After the error shell's base rules, which it narrows. */
@media (max-width: 47.9375rem) {
    .errorshell .message {
        padding: 20px 18px;
    }

    .errorshell .message__actions .button.button--main {
        width: 100%;
        padding-inline: 12px;
        font-size: 16px;
    }
}

/* ==== DESIGN 2026 — THE SHARED SHELL, round 1 (advisor's design review 11:30, D1) =============
 * The footers' wordmark tracked like the bar's (.p-mark: 700, 0.18em, capitals), and the guest
 * footer on a phone as MobileFamily draws it (.ph-foot): 18/16/20 inside, 10 between its lines,
 * and its two destinations as 48px outlined pills. Qualified by the footer so public.css, which
 * loads after this sheet on /materials, does not undo it. */
.publicfoot .publicfoot__brand,
.sitefoot .page__footer-brand {
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    white-space: nowrap;
}

@media (max-width: 47.9375rem) {
    .publicfoot .publicfoot__inner {
        gap: 10px;
        padding: 18px 16px 20px;
        font-size: 13px;
    }

    .publicfoot .publicfoot__brand {
        font-size: 14px;
    }
}

/* Selects: the boards' chevron (select.fld) in Lasting Blue instead of the browser's arrow, as a
 * file: the CSP allows no data: image (SecurityHeaders). Not the converter's select, which is the
 * developers' component, and not a disabled select, which keeps its quiet ground and the
 * browser's own arrow (the boards' chevron would read as an active control). The file repeats Lasting Blue as a hex:
 * see the note beside --nn-lasting-blue in tokens.css. */
select.field__input:not(.converter *):not(:disabled),
.field__select:not(.converter *):not(:disabled) {
    appearance: none;
    padding-right: var(--control-padding-chevron);
    background: var(--colour-surface) url('../img/chevron-down.svg') no-repeat right var(--control-chevron-inset) center;
}

/* --- The signed-in bar inside the page's content box (D1 item 1) ------------------------------
 * "Log ud" ended at 1405 at 1440, past the 64px gutter the cards keep (advisor's design review),
 * and for an administrator well past the window (advisor, 15:10). The row takes the boards'
 * distances instead of one 28px gap (27 after the mark, at least 28 before the person, 17 before
 * the way out), the rule before the way out goes, and an administrator's way in is a small chip
 * after the destinations instead of a seventh full-size one. Below 1440 the links take the tablet
 * board's 12px padding. The name stays whole or undrawn (F-043, App\Support\BarName). */
.bar__admin {
    display: none;
}

@media (min-width: 64rem) {
    .appbar .topbar {
        min-width: 0;
        column-gap: 0;
    }

    .appbar .topbar .gatemark {
        margin-right: 27px;
    }

    .appbar .bar {
        flex: 1 1 auto;
        margin-right: 28px;
    }

    /* ONE SPACING BETWEEN EVERY DESTINATION, THE ADMIN CHIP INCLUDED (Kenneth on staging, 4/10). The
     * boards' 2px let the filled pill of the current page touch its neighbour, and the Admin chip,
     * pushed to the row's far end, touched it whenever the row was full. 8px everywhere; the chip
     * follows the last destination at the same distance. Measured to fit at 1024 for a Danish
     * captain who is also an administrator, the widest row. */
    .appbar .topbar .bar {
        gap: var(--space-2xs);
    }

    .appbar .topbar:has(.bar__admin) .bar {
        margin-right: 12px;
    }

    .appbar .whoami {
        flex: none;
        margin-left: auto;
    }

    /* No rule between the person and the way out: the boards set the two 17px apart, nothing more. */
    .appbar .topbar .whoami {
        border-right: 0;
        padding-right: 0;
    }

    .appbar .bar__admin {
        display: inline-flex;
        flex: none;
        align-items: center;
        min-height: 44px;
        padding: 0 14px;
        border: 2px solid var(--colour-primary);
        border-radius: 999px;
        color: var(--colour-primary);
        font-size: 13px;
        font-weight: var(--font-weight-bold);
        text-decoration: none;
    }

    .appbar .bar__out {
        flex: none;
        margin-left: 17px;
    }
}

/* An administrator below 1440: the name is not drawn there anyway (F-043), so the chip stands in
 * for the decorative initials (the person stays in the accessibility tree), and the links and
 * chip take 10px sides. Measured to fit at 1024 and 1280 in DejaVu Sans, which is wider than the
 * Arial testers see. */
@media (min-width: 64rem) and (max-width: 89.99rem) {
    .appbar .topbar:has(.bar__admin) .whoami__initials {
        display: none;
    }

    .appbar .topbar:has(.bar__admin) .bar .bar__link {
        padding-inline: 10px;
    }

    .appbar .topbar:has(.bar__admin) .bar__admin {
        padding: 0 10px;
    }
}

/* The signed-in phone bar (D1 item 5), as MobileFamily draws it: the mark tracked like every
 * other bar (it fits beside one avatar; the guest bar's untracked mark was for its language
 * pill) and the avatar at the right edge. */
@media (max-width: 47.9375rem) {
    .appbar .topbar .gatemark {
        font-size: 14px;
        letter-spacing: 0.18em;
    }

    .appbar .topbar {
        flex-wrap: nowrap;
    }

    .appbar .topbar .whoami {
        margin-left: auto;
    }
}

/* Under 360 the full tracking and the avatar need more than the row has: ease the tracking. */
@media (max-width: 22.4375rem) {
    .appbar .topbar .gatemark {
        letter-spacing: 0.1em;
    }
}

/* Space above the footer (D1 item 6): the boards leave about 40px between the last card and the
 * footer; the page's 48 bottom padding plus the footer's 64 margin left 112. */
.page:has(~ .sitefoot) {
    padding-bottom: 0;
}

.sitefoot {
    margin-top: 40px;
}

/* The footer's language control (D1 item 2), as the boards draw it (.p-foot-lang, .seg-ink):
 * "Sprog" in the quiet on-ink voice, then one outlined pill with the two languages, the current
 * one filled white. Endonyms here, where the bar's pill shows the two-letter codes. Same markup
 * and accessible names as everywhere else (partials/language-switcher). */
.sitefoot .language {
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 13px;
}

.sitefoot .language__label {
    color: var(--board-on-ink-muted);
}

.sitefoot .language__options {
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    border: 2px solid var(--board-on-ink-muted);
    border-radius: 999px;
}

.sitefoot .language__current,
.sitefoot .language__choice {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 14px;
    border: 0;
    border-radius: 999px;
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-decoration: none;
}

.sitefoot .language__current {
    background: var(--colour-surface);
    color: var(--colour-primary);
}

.sitefoot .language__choice {
    background: transparent;
    color: var(--colour-text-inverse);
    cursor: pointer;
}

.sitefoot .language__code {
    display: none;
}

/* === PARTICIPANT 2026 — DESIGN REVIEW D2 =========================================================
 *
 * The advisor's round-1 comparison of every participant screen against its board. Each rule names
 * the item it answers, so a later reader can find the finding it closes.
 */

/* --- Mit hold, the roster (D2.2) ---------------------------------------------------------------- */

/* A NAME IS 16/700, as the board draws it and as Stilling draws its names. */
.roster-panel .roster-table__person {
    font-size: 16px;
    font-weight: var(--font-weight-bold);
}

/* THE CAPTAIN CHIP IS THE BOARD'S `.chip`: sentence case, 12/700, untracked. White on the reader's
 * own tinted row (`.chip-white`, the rule further up); the tint elsewhere, so on a white row the
 * pill keeps an edge. The words carry the role either way. */
.roster-panel .roster-table__badge {
    margin-left: 12px;
    padding: 5px 10px;
    font-size: 12px;
    line-height: 1;
    letter-spacing: 0;
    text-transform: none;
}

@media (min-width: 80rem) {
    /* ONE CONTINUOUS RULE UNDER EACH ROW. The name cell was a flex box, which takes a `td` out of
     * table layout: its border was drawn on its own box, a line off the other cells' rule, and the
     * row's rule broke where the name column ended. As a real cell it shares the row's line; the
     * mark, the name and the chip sit inline on the cell's middle instead. */
    .roster-panel .roster-table td.roster-table__name {
        display: table-cell;
        vertical-align: middle;
        white-space: nowrap;
    }

    .roster-panel .roster-table td.roster-table__name > * {
        vertical-align: middle;
    }

    .roster-panel .roster-table td.roster-table__name .roster-table__mark {
        display: inline-flex;
        margin-right: 12px;
    }
}

@media (min-width: 88rem) {
    /* AN ADDRESS ON ONE LINE WHERE THE TABLE IS A TABLE. The `<wbr>` after "@" is the phone's
     * break; here the address column is given the room. The table is `table-layout: fixed`, so
     * the header cells state the widths: the state, date and action columns narrow to what their
     * content needs (the board draws 140 / 104 / 216) and the address takes the rest. */
    .roster-panel .roster-table--invites thead th:nth-child(2) {
        width: 180px;
    }

    .roster-panel .roster-table--invites thead th:nth-child(3) {
        width: 128px;
    }

    .roster-panel .roster-table--invites thead th:nth-child(4) {
        width: 256px;
    }

    .roster-panel .roster-table--invites td.roster-table__address {
        white-space: nowrap;
    }
}

/* An invited address is the row's name, at the semibold MyTeam.dc.html draws it (the last
 * participant pass: it was body weight) — a step lighter than a member's name, as the board keeps
 * the two apart. */
.roster-panel .roster-table--invites td.roster-table__address {
    font-weight: var(--font-weight-semibold);
}

/* --- Stilling (D2.3) ------------------------------------------------------------------------------ */

/* NAMES ARE BOLD, AND SO IS EVERY FIGURE (Kenneth, 2026-09-27): Medlemmer, Indtastet and the
 * average share one weight and colour, tabular and right-aligned (.board-table__figure). */
.board-panel .board-table .board-table__name {
    font-weight: var(--font-weight-bold);
}

/* THE PALE GROUND ALONE MARKS THE READER'S ROW, with the word "dig" and aria-current. The gold
 * rule down its left edge is not on the board. */
.board-panel .board-table__row--you > *:first-child {
    box-shadow: none;
}

/* --- Konkurrencer (D2.4) -------------------------------------------------------------------------- */

/* THE TEAM ROW UNDER THE TITLE (family test, 25 Sep): one line on the content grid, full width,
 * instead of a box floating top-right beside nothing. Waiting in the pending colours with the
 * link onward; ready in the positive ones, the sentence alone. The word carries the state; the
 * dot and the tint agree with it. */
.teamrow {
    padding: 14px 20px;
    border-radius: var(--radius-xl);
    background: var(--board-pending-ground);
    color: var(--board-pending-text);
}

.teamrow--ready {
    background: var(--board-positive-ground);
    color: var(--board-positive-text);
}

.teamrow__line {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 10px;
    margin: 0;
    font-size: 16px;
    font-weight: var(--font-weight-regular);
    line-height: 1.4;
}

.teamrow__label,
.teamrow__state {
    margin: 0;
    font-size: inherit;
    font-weight: var(--font-weight-bold);
    color: inherit;
}

.teamrow__dot {
    flex-shrink: 0;
    width: 8px;
    height: 8px;
    border-radius: var(--radius-pill);
    background: var(--colour-warning);
}

.teamrow--ready .teamrow__dot {
    background: var(--colour-success);
}

.teamrow .text-link {
    color: var(--colour-text);
    font-size: inherit;
    font-weight: var(--font-weight-bold);
}

/* On a phone the row wraps, and a separator left at the end of a line reads as a stray mark. */
@media (max-width: 47.9375rem) {
    .teamrow__sep {
        display: none;
    }
}

/* A team the published result has no row for: a fact, not a state, so no state colour. */
.teamrow--neutral {
    background: var(--board-closed-ground);
    color: var(--colour-text);
}

/* The fact tiles follow each card's words (family test, 25 Sep): the rules that stretched the
 * card body and pushed the tiles to its floor with `margin-top: auto` are gone, so the base
 * `.competition-list .competition { align-content: start }` above holds. */

/* --- Mine skridt (D2.5) --------------------------------------------------------------------------- */

/* --- Support (D2.6) ------------------------------------------------------------------------------- */

/* KAMPAGNENS DATOER: THE LABEL LEFT, THE VALUE RIGHT ON ONE LINE, THE LABEL WRAPPING IF LONG — in the two-column layout,
 * where the panel is the 400px aside. At 16px "Tilmeldingen lukker" and "søn. 27. sep. kl. 23:59"
 * need 361px of a 352px row and both broke in two; at 15px, 12 apart, the longest pair fits.
 * Narrower, the panel is the page's width and a label may wrap above its value (copilot-187/189:
 * one line at any width overflowed a 320 phone). */
@media (min-width: 64rem) {
    .helpgrid .datepanel__row {
        flex-wrap: wrap;
        gap: 12px;
        font-size: 15px;
    }

    /* A LONG LABEL MAY WRAP BESIDE THE VALUE, and the row may wrap as a last resort, so with enlarged
     * text the value drops under its label rather than overlapping it. The value itself breaks only
     * between its day and its clock (App\Support\Deadline's non-breaking spaces; the later
     * `.helpgrid .datepanel__row dd` rule lets it wrap there, audit 1006 D9). */
    .helpgrid .datepanel__row dt {
        flex: 1 1 0;
        min-width: min-content;
    }
}

/* === THE SIGN-IN FORM ============================================================================
 * The form /sign-in carries (auth/partials/sign-in-form with `entry`): the envelope inside the field,
 * the field and the button stacked, the hint, the error's ink. The page around it is the v4 sign-in
 * layer at the end of this file. */

/* The envelope inside the field: the wrapper is the field's box, the icon sits 20px in from its
 * left edge, and the text starts after it. Decorative (the label names the field). */
.gate__envelope {
    position: relative;
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
}

.gatecard--signin .gate__envelope .field__input {
    width: 100%;
    margin: 0;
    padding-left: 54px;
}

.gate__envelope .lineicon {
    position: absolute;
    top: 50%;
    left: 20px;
    width: 22px;
    height: 22px;
    transform: translateY(-50%);
    color: var(--colour-text-muted);
    pointer-events: none;
}

/* THE FIELD AND THE BUTTON STACK, full width, as Kenneth's mock draws them (advisor design review of
 * #196): beside the button the field was about 310px, and a 40-character Novo address scrolled
 * inside it. Stacked, the field is the form's 560px at every width. One class more than the
 * landing's `.gatecard--landing .gate__entry-submit`. */
.gatecard.gatecard--signin .gate__entry {
    flex-direction: column;
    align-items: stretch;
}

.gatecard.gatecard--signin .gate__entry-submit {
    width: 100%;
    justify-content: center;
    gap: 8px;
}

.gatecard--signin .gate__hint {
    margin-top: 12px;
    color: var(--colour-text-muted);
    font-size: 0.8125rem;
}

/* The error as the front page's (advisor 5/10 07:20, carried to /sign-in): above the field, 14px bold
 * in ink, led by the item-3 "!" on the status card's Lava Red — the disc is the front page's rule,
 * whose selector list this form joins. No new red: #B0562F's outline mark goes from this form. */
.gatecard--signin .gate__form .field__error {
    margin: 0 0 6px;
    color: var(--colour-text);
    font-size: 0.875rem;
    font-weight: var(--font-weight-bold);
}

/* The landing's same form, the same room and the same ink. A refused address now takes focus back
 * into the field (#256), and its 3px ring, 3px out, ran through the last line of the message above
 * it at desktop widths (design review of #256). And the words were #B0562F on the warm ground,
 * 4.46:1 — under 1.4.3's 4.5 — so the words take the status ink and the mark keeps the negative
 * colour. */
.gatecard--landing .gate__form .field__error {
    margin-bottom: 12px;
    color: var(--colour-status-text);
}

.gatecard--landing .gate__form .field__error-mark {
    color: var(--board-negative-text);
}

/* The phone: the form has no box of its own inside the card. */
@media (max-width: 47.9375rem) {
    .gatecard--signin .gate__form {
        padding: 0;
        border: 0;
        border-radius: 0;
        background: none;
    }
}

/* --- The rest of the sign-in family: check-email, the expired link, continue ------------------------
 * The card centred (the footprints beside it went on 2026-09-27, Kenneth); on a phone the footprints
 * sit small above the card's right edge. Check-email's card is wider so
 * the echoed address fits on one line at 1440. */
.gateshell:not(.gateshell--landing) .gatemain--split .gatemain__inner {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    gap: 32px;
}

.gateprints .prints {
    width: 120px;
    height: 120px;
}

.gateshell .gatecard.gatecard--mail,
.gateshell .gatecard.gatecard--code {
    max-width: 560px;
}

@media (max-width: 47.9375rem) {
    .gateshell:not(.gateshell--landing) .gatemain--split .gatemain__inner {
        flex-direction: column;
        align-items: stretch;
        gap: 8px;
    }

    .gateprints {
        order: -1;
        align-self: flex-end;
    }

    .gateprints .prints {
        width: 56px;
        height: 56px;
    }
}

.gatecard__icon .lineicon {
    width: 26px;
    height: 26px;
    color: var(--colour-primary);
}

.gate__sent-address--line {
    display: block;
    margin-top: 4px;
    color: var(--colour-primary);
    overflow-wrap: anywhere;
}

.gatecard__lede--then {
    margin-top: 12px;
}

/* === A FIELD REACHED BY ITS ADDRESS LANDS WITH ITS LABEL IN VIEW (advisor 25 Sep, §2) ============
 * The landing's error-summary link to #email put the field at the window's top edge, its label cut
 * off above it. Every field an in-page link can reach keeps room for its label and a little air. */
input[id],
select[id],
textarea[id] {
    scroll-margin-top: 96px;
}

/* === NAV PILLS (advisor 25 Sep 15:45 §3, Kenneth 15:55) ===========================================
 * One rule for every bar: a destination is plain text at rest, sits on a soft pill of the v4 band
 * tint on hover and keyboard focus, and the current page is the filled ink pill. No underline on a
 * nav link; links inside running text keep theirs (1.4.1). Focus stays the global 3px ring on top of
 * the pill. The guest bar takes the board's own geometry (GuestAuth .g-links: 12px sides, 8 apart),
 * the participant bar already had the shape and now shares the ground, and the admin sub-navigation
 * gains the ground it lacked. The ink admin bar keeps its raised-ink hover, which is the same idea on
 * a dark surface. */
.gatebar--shared .gatebar__end {
    gap: 8px;
}

.gatebar__link {
    padding: 0 12px;
    border-radius: var(--radius-pill);
}

.gatebar__link:hover,
.gatebar__link:focus-visible,
.appbar .bar__link:hover,
.appbar .bar__link:focus-visible,
.appbar .bar__admin:hover,
.appbar .bar__admin:focus-visible {
    /* The v4 band tint, not the Now Turquoise tint: Now Turquoise only ever stands on Lasting Blue
     * (design v4; advisor 2026-10-02 09:15). */
    background: var(--colour-surface-band);
    color: var(--colour-primary);
    text-decoration: none;
}

.gatebar__link[aria-current='page'],
.gatebar__link[aria-current='page']:hover,
.gatebar__link[aria-current='page']:focus-visible {
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
    text-decoration: none;
}

/* The wordmark links home and is not underlined either; its focus ring is the global one. */
.gatebar__brand:hover .gatemark {
    text-decoration: none;
}

/* The current page keeps its own fill under the pointer and focus: written after the hover rule
 * above, which would otherwise repaint it with the band tint. */
.appbar .bar__link[aria-current='page']:hover,
.appbar .bar__link[aria-current='page']:focus-visible {
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
}

/* The admin sub-navigation keeps the locked board's current page, the tinted block
 * (AdminCampaign .a-sub a[aria-current]: two rows of filled pills would read as one menu). Its hover
 * and focus take a quieter ground than that tint, so a link under the pointer never looks more
 * current than the page you are on. */
.adminsub__link:hover,
.adminsub__link:focus-visible {
    background: var(--board-quiet-row);
    color: var(--colour-primary);
    text-decoration: none;
}

.adminsub__link.adminsub__link--on:hover,
.adminsub__link.adminsub__link--on:focus-visible {
    background: var(--colour-surface-field);
    color: var(--colour-text);
}

/* === BRAND-ONLY FOOTERS: THE PHONE BAR TAKES "SIGN IN" (advisor 25 Sep 16:35, §4b) =============
 * The guest footer carries no destinations now, so on a phone the bar shows the one that matters,
 * "Sign in" (or "Mine skridt" when signed in), as a small outlined pill beside the language pill.
 * "Campaign materials" stays off the phone bar: the landing's own button reaches it. */
@media (max-width: 47.9375rem) {
    .gatebar--shared .gatebar__end {
        display: flex;
    }

    .gatebar--shared .gatebar__link--secondary {
        display: none;
    }

    .gatebar--shared .gatebar__link--primary {
        min-height: 48px;
        padding: 0 12px;
        border: 2px solid var(--colour-primary);
        font-size: 14px;
        font-weight: var(--font-weight-bold);
    }

    /* The row wraps only when it cannot fit: the pill then takes its own line at the right. Signed
     * in, "Mine skridt" is wider than "Sign in", and a tracked mark from 24rem leaves little spare. */
    .gatebar--shared .gatebar__inner {
        flex-wrap: wrap;
    }

    .gatebar--shared .gatebar__end {
        margin-left: auto;
    }

    /* With the pill beside the language, the tracked mark takes two lines on a phone; they sit
     * left, on the gutter, like every other line of the page. Onboarding's bar has no pill and
     * keeps its one-line mark (MobileFamily). */
    .gatebar--shared:has(.gatebar__end) .gatemark {
        text-align: left;
    }

    /* Two lines at most, as MobileFamily draws it (.p-mark at about 9.5em; 8.5em here: "CHALLENGE" is 116px
     * of its 119, and "Mine skridt", 117px, then shares the row at 390): without a cap the wrapping row
     * lays the mark out on one line first and sends the pill to a second row at every phone width,
     * and `min-content` could break it at every space. */
    .gatebar--shared:has(.gatebar__end) .gatebar__brand {
        flex: 0 1 auto;
    }

    .gatebar--shared:has(.gatebar__end) .gatemark {
        display: block;
        max-width: 8.5em;
    }
}

/* === THE GUEST PHONE BAR AT 320 (night queue: "check it breathes at 320") =======================
 * Only below 22.5rem (360px), where the row wrapped to 114px: 360 and up already hold one row and
 * are untouched (design review). Scoped to bars that carry both the language switch and the
 * destinations: onboarding's bar has no destinations, and the continue page's has neither (Copilot
 * on #208). The untracked wordmark is capped at its longest word (two lines, about 90px), the gaps are
 * 6px (the 3px focus ring, 3px out, still clears the neighbour), and the language segments and the
 * pill give up 2px a side. EN and DA then share one 58px row at 320; every target stays at least
 * 44 wide and 48 tall. A signed-in "Mine skridt" is wider and still wraps cleanly. */
@media (max-width: 22.49rem) {
    .gatebar--shared:has(.gatebar__end):has(.language) .gatemark {
        max-width: min-content;
    }

    .gatebar--shared:has(.gatebar__end):has(.language) .gatebar__inner {
        column-gap: 6px;
    }

    .gatebar--shared:has(.gatebar__end):has(.language) .language__current,
    .gatebar--shared:has(.gatebar__end):has(.language) .language__choice {
        padding-inline: 12px;
    }

    .gatebar--shared:has(.gatebar__end):has(.language) .gatebar__link--primary {
        padding: 0 10px;
    }
}

/* === THE ERROR PAGES IN THE GATE FAMILY (advisor 25 Sep, 1d) =====================================
 * 403, 404, 419 and 500 (layouts/error): the card centred with the footprints to its right, as on
 * check-email and the expired link; on a phone the footprints sit small above the card's right edge.
 * The 503 page is standalone on purpose (its own stylesheet, no database) and is not part of this. */
.errormain {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    gap: 32px;
}

.errormain > .message {
    /* A definite width, not shrink-to-content, so the one action ("Tilbage til Novo Step
     * Challenge") keeps its line (design review: shrinking to the message broke the Danish button
     * onto two lines). */
    flex: 0 1 520px;
    min-width: 0;
}

/* The page's box holds the 520 card and its sides: the error shell's .page is 42rem including 64px
 * sides, which left the card 392. */
@media (min-width: 48rem) {
    .errorshell .page {
        max-width: calc(520px + 128px);
    }
}

/* FROM 48rem THE CARD STANDS ALONE, CENTRED (Kenneth, 2026-09-27: "de fødder er for grimme – fjern
 * dem og sæt boksen i midten"). Every single-card gate page and every error page: the footprints
 * beside the card, small or as a trail, are gone, so the card is the page. A phone is unchanged: the
 * small mark stays above the card's right edge there. /sign-in and the front page are pages
 * (`main.frontpage`) with no .gateprints aside. */
@media (min-width: 48rem) {
    .gateprints {
        display: none;
    }
}

@media (max-width: 47.9375rem) {
    .errormain {
        flex-direction: column;
        align-items: stretch;
        gap: 8px;
    }

    /* In the column the flex basis is a height: the desktop 520px would make a tall blank card
     * (Copilot on #207). The card takes its content's height here. */
    .errormain > .message {
        flex: 0 1 auto;
    }
}

/* === THE GATE CARD'S PARTS (advisor 25 Sep, 1d) ==================================================
 * An icon tile at the top of every gate card (partials/gate-tile), one primary pill with the arrow
 * (partials/button-arrow), and what is not the primary under a hairline. */
.gatecard__icon + .gatecard__chip,
.gatecard__icon + .message__code {
    margin-top: 0;
}

.message > .gatecard__icon {
    margin-bottom: 16px;
}

/* The arrow sits after the words, 10px from them, and never shrinks. By its own class, so the
 * landing's and /sign-in's entry buttons, which space their arrow with a gap, are not matched
 * (design and code review). */
.button__arrow {
    flex-shrink: 0;
    margin-left: 10px;
}

/* On a phone the error pill is full width so the English label stays one line at 390 (the rule
 * above that says so); the arrow would tip "Back to Novo Step Challenge" into two, so there it is
 * left out. The Danish label wraps at 390 with or without it, as it did before. */
@media (max-width: 47.9375rem) {
    .errorshell .message__actions .button__arrow {
        display: none;
    }
}

/* The foot as a block of lines: a secondary link, then a quiet sentence. */
.gatecard__foot > p {
    margin: 0;
}

.gatecard__foot > p + p {
    margin-top: 10px;
}

.gatecard__secondary .text-link {
    min-height: 44px;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
}

.gatecard__provenance {
    font-size: 14px;
    line-height: 1.5;
}

/* STILLING'S TWO CONTROLS ON ONE ROW FROM A LAPTOP UP (advisor sweep 1): "Vis [scope]" at the
 * left and "[Alle skridt | Kun skridt]" at the right, rather than stacked because the box was held
 * to 32rem and wrapped. The note, when there is one, keeps a line of its own. A phone stacks them. */
@media (min-width: 64rem) {
    .pagestack > .filters {
        width: auto;
        align-items: center;
        justify-content: space-between;
        column-gap: 24px;
    }

    .pagestack > .filters > .filters__note {
        flex: 1 1 100%;
    }
}

/* === EVERY FOOTER IS THE WORDMARK PLUS novohealth (Kenneth, 2026-09-25 16:35) ================
 * The operator sentence is gone from every footer. On a phone the error layout's footer kept the
 * 82px the participant layout reserves under its fixed tab bar, an empty ink band on a page that
 * has no tab bar (advisor sweep 1); the error footer ends at its content. */
@media (max-width: 47.9375rem) {
    .errorshell .sitefoot {
        padding-bottom: 0;
    }
}

/* === ONE FOOTER ON A PHONE (final guest pass, b2) ============================================
 * The guest footer stood 90px at 390 and the error and participant footers 125px for the same
 * two lines, because the site footer kept its desktop padding and gap. On a phone every ink
 * footer takes MobileFamily's .ph-foot: 18px above, 16 at the sides, 20 below, 10 between the
 * lines. The participant layout's 82px under the fixed tab bar is the footer's own padding and
 * is not touched. Qualified by the error shell too, whose padding-inline rule is more specific. */
@media (max-width: 47.9375rem) {
    .sitefoot .sitefoot__inner,
    .errorshell .sitefoot .sitefoot__inner {
        padding: 18px 16px 20px;
        gap: 10px;
    }
}

/* === THE ADMIN CODE PAGES IN THE GATE CARD (Kenneth 25 Sep 20:50: "not very pretty") =========
 * Enrolment, the challenge and re-authentication were bare text and a small field on an empty
 * participant page. They are gate cards now: 560 wide like check-email (the width rule is
 * check-email's, above), the shield tile, the footprints beside it. The code is the card's one
 * field, so it is large and centred, its six digits spaced (a code, not a sentence); the pill
 * below it takes the card's width. AdminCodePages.dc.html draws it. */

.gatecard--code .mfa__form {
    margin-top: 24px;
}

.gatecard--code .mfa__code {
    /* The card's one field wears the primary edge, as /sign-in's does and the board draws it: the
     * gate card's soft border is for secondary fields and is too faint to find this one by. */
    border: 2px solid var(--colour-primary);
    max-width: none;
    width: 100%;
    height: 64px;
    font-size: 28px;
    font-weight: var(--font-weight-semibold);
    text-align: center;
    /* The code's own tracking, five times over: a gap wide enough to keep a transposed pair
     * visible. It trails the last digit too, so the same amount before the first keeps the row
     * centred. */
    letter-spacing: calc(var(--tracking-code) * 5);
    padding-inline: calc(var(--tracking-code) * 5) 0;
}

/* A refused code keeps its red edge: the primary edge above would otherwise win, being later at
 * the same specificity (the trap the rule at .gate__form .field__input[aria-invalid] records). */
.gatecard--code .mfa__code[aria-invalid='true'] {
    border-color: var(--colour-danger);
}

/* The field's own margins are the form's here: 24 above it, 20 to the pill. */
.gatecard--code .mfa__form .field {
    margin: 0;
}

.gatecard--code .mfa__actions {
    margin-top: 20px;
}

.gatecard--code .mfa__actions .button {
    width: 100%;
    margin-top: 0;
}

/* At 320 "Afslut opsætning" and its arrow fit one line only when the pill gives up some side
 * padding. */
@media (max-width: 22.49rem) {
    .gatecard--code .mfa__actions .button {
        padding-inline: 16px;
    }
}

/* Enrolment's two steps, numbered by the list itself: the number in a small tile-ground disc
 * beside a step title, the QR and the key under the first. */
.gatecard--code .mfa__steps {
    list-style: none;
    counter-reset: mfa-step;
    margin: 24px 0 0;
    padding: 0;
    gap: 24px;
}

.gatecard--code .mfa__step {
    counter-increment: mfa-step;
}

.gatecard--code .mfa__step-title {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    color: var(--colour-primary);
}

.gatecard--code .mfa__step-title::before {
    content: counter(mfa-step);
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    /* Ice Blue, as every small round tile in design v4; the Now Turquoise tint stays on Lasting Blue. */
    background: var(--colour-surface-tile);
    font-size: 14px;
}

/* The QR and the key as the board draws them in the card: the QR on the field edge, the key on
 * the field ground. THE 160PX IS THE CODE'S, NOT THE FRAME'S (2FA QA, 2026-09-26): with the frame's
 * padding and border inside it the code itself drew at 134px, under the 160 a phone camera at arm's
 * length is asked to read; content-box puts the padding outside, so the frame is 186px. */
.gatecard--code .mfa__qr {
    box-sizing: content-box;
    max-width: 160px;
    padding: 12px;
    border-color: var(--colour-border-field);
    border-radius: 12px;
}

.gatecard--code .mfa__manual-key {
    font-size: 17px;
    padding: 10px 12px;
    /* The v4 band tint (#F2F2FA), where the 2026 board laid its pale blue. */
    background: var(--colour-surface-band);
    border-radius: 8px;
}

.gatecard--code .mfa__step .mfa__form {
    margin-top: 0;
}

.gatecard--code .mfa__out {
    margin-top: 24px;
}

/* === THE GUEST SCREENS AGAINST THEIR BOARDS (night queue 2, b2 item 3) =======================
 * Measured landmark by landmark against Main, GuestAuth and GuestOnboarding at 1440; these are the
 * differences over 8px that the product owned.
 * - The landing and /sign-in: the entry form's first field kept the gate card's 24px on top of
 *   the form's own 32, so "Work email" sat 24px below the board's.
 * - The tile: 22px under it against the boards' 18 (sign-in family) and 16 (onboarding).
 * - The "Link no longer valid" chip: 32px tall with 20 under it; the board's chip is 24 (12px words,
 *   5px 10px), 16 above the heading. Set on the chip's own rule, so roster-closed's matches.
 * - Onboarding: the first field 20 under the lede, the selects 52 as the board's .fld draws them,
 *   where 24 and 56 put the create-team pill 42px below the board's.
 * - The one action straight under a card's head: 22 above it, not 32.
 * - The pulse's labels ("Steps counted so far", "Participants") from 48rem: 11px at their own line
 *   height, as Main's .lp-klabel and GuestAuth's .si-lab set them (MobileFamily's phone pulse is a
 *   different drawing, recorded, not this rule's), and the state row and the freshness line
 *   on a 1.2 line; 12px on a 1.55 line added 27px to the panel by its last line. */
.gatecard--landing .gate__form .field:first-of-type,
.gatecard--landing .gate__form > .gate__label:first-of-type {
    margin-top: 0;
}

/* The card ledes at the boards' 15px (advisor, night queue 3: "match the boards"): GuestAuth's
 * .ga-lede, GuestOnboarding's and AdminCodePages' ledes, and so every other gate card's lede too —
 * the admin entrance, continue, join and its confirmation. The landing's and /sign-in's 19px lede
 * is their own board's and is not a card lede. The type scale's step, so a larger browser text size
 * still reaches it. */
.gatecard:not(.gatecard--landing) .gatecard__lede {
    font-size: var(--font-size-sm);
}

/* A card's one action straight under its head: 22 above it, as the board draws it (the dead team
 * link), not the 32 the card's buttons take elsewhere. */
.gatecard__head + .button {
    margin-top: 22px;
}

.gatecard .gatecard__icon {
    margin-bottom: 18px;
}

/* The onboarding boards draw 16 under the tile (GuestOnboarding .go-ico + 16). */
.gatecard--onboarding .gatecard__icon {
    margin-bottom: 16px;
}

.gatecard--onboarding .gate__form > .field:first-of-type,
.gatecard--onboarding .gate__form > .gate__label:first-of-type {
    margin-top: 20px;
}

.gatecard--onboarding .placegroup__title {
    line-height: 16px;
}

.gatecard--onboarding .placegroup__fields {
    gap: 10px;
    margin-top: 0;
}

.gatecard--onboarding .placegroup__note {
    margin-top: 0;
}

/* On a phone the landing's heading starts under the bar as MobileFamily draws it (m-head, 8px
 * down), not 16px further into a card the phone board does not draw. */
@media (max-width: 47.9375rem) {
    .gatecard--landing:not(.gatecard--signin) {
        padding-top: 0;
    }
}

/* === THE GATE SHELL COMPOSITION (external UX review, advisor 2026-09-26 07:50) ==================
 * On a desktop every gate page — the sign-in family, the error pages, onboarding and the team pages,
 * the admin entrance and code pages — fills the height between bar and footer, the card centred in
 * it, both ways. The footprints trail that walked beside the card (#245) is gone (Kenneth,
 * 2026-09-27): the card is centred at its own width. /sign-in and the front page render
 * `main.frontpage`, not `.gatemain`, so nothing here reaches them. A phone is unchanged. */
@media (min-width: 64rem) {
    /* THE HEIGHT BETWEEN BAR AND FOOTER, the card centred in it. The shells are already full-height
     * flex columns with main growing into the rest; main only has to centre. */
    .gateshell:not(.gateshell--landing) .gatemain,
    .errorshell .page {
        display: flex;
        align-items: center;
    }

    .gateshell:not(.gateshell--landing) .gatemain__inner {
        width: 100%;
    }

    /* A CARD PAGE: its only aside is the phone's footprints, hidden from 48rem, so one column with
     * the card centred in it at its own width. The base split rule would give it a second column. */
    .gateshell:not(.gateshell--landing) .gatemain--split .gatemain__inner {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        align-items: center;
    }

    .gateshell:not(.gateshell--landing) .gatemain--split .gatecard {
        justify-self: center;
    }

    /* The error pages: the message centred on the layout's width. */
    .errorshell .page {
        width: 100%;
        max-width: 90rem;
    }

    .errormain {
        display: grid;
        width: 100%;
        grid-template-columns: minmax(0, 1fr);
        align-items: center;
    }

    .errormain > .message {
        justify-self: center;
        width: 100%;
        max-width: 520px;
    }
}

/* 5. THE ERROR PAGES ON THE GATE'S GUTTER from 80rem (copilot-245), so an error card sits on the
 * same frame as a gate card. */
@media (min-width: 80rem) {
    .errorshell .page {
        padding-inline: 96px;
    }
}

/* === A FOCUSED FIELD IS ONE THICK LINE (Kenneth, 2026-09-27 07:55: "hvorfor dobbelt linie her") ===
 * The ring every control takes — 3px, 3px clear of its edge — read on a text field as a second
 * line around the field's own border. A field that takes text or a choice (input, select,
 * textarea) shows focus as ONE band instead: its own border turns to the focus ink, and a 3px ink
 * band is laid directly inside it (an inset shadow, so it touches the border whatever its width,
 * and the field keeps its size). On a field that already rests on a 2px ink edge — the step, the
 * sign-in and the code fields — focus is a 5px band against its 2px rest, a change anyone sees
 * (design review: an ink line over an ink edge was a 1px change). A refused field keeps its red
 * edge outside the band, so the refusal still shows while it has focus. In forced colours, where
 * shadows are not drawn, the outline is the system's ring. Buttons, links,
 * summaries, checkboxes and radios keep the offset ring. One rule, participant and admin. */
:is(input:not([type='checkbox'], [type='radio'], [type='range'], [type='file'], [type='color'], [type='submit'], [type='button'], [type='reset'], [type='image']), select, textarea):focus-visible {
    /* The inward outline lies over the border and the band's first pixel, so no seam shows
     * between them; it is also the ring forced colours draw. */
    outline: var(--focus-ring-width) solid var(--colour-focus);
    outline-offset: calc(-1 * var(--focus-ring-width));
    border-color: var(--colour-focus);
    box-shadow: inset 0 0 0 var(--focus-ring-width) var(--colour-focus);
}

/* Refused: the red edge stays, and the ink starts inside it. */
:is(input, select, textarea)[aria-invalid='true']:focus-visible {
    outline-offset: calc(-1 * (var(--focus-ring-width) + var(--border-width-strong)));
    border-color: var(--colour-danger);
}

/* The converter's minutes are one composite field whose wrapper owns the edge and the focus; it is
 * the same band, drawn on the wrapper, and keeps its red edge when refused. */
.converter .field__withunit:has(.field__input:focus-visible) {
    outline: var(--focus-ring-width) solid var(--colour-focus);
    outline-offset: calc(-1 * var(--focus-ring-width));
    border-color: var(--colour-focus);
    box-shadow: inset 0 0 0 var(--focus-ring-width) var(--colour-focus);
}

.converter .field__withunit:has(.field__input[aria-invalid='true']:focus-visible) {
    outline-offset: calc(-1 * (var(--focus-ring-width) + var(--border-width-strong)));
    border-color: var(--colour-danger);
}

/* Its inner input draws nothing of its own: no outline (above) and no band (design review). */
.converter .field__withunit .field__input:focus-visible {
    box-shadow: none;
}

/* THE LOGO STAYS CENTRED ON MINE OPLYSNINGER (advisor, 2026-09-27 12:25). That page holds the
 * language itself and draws no switch in its footer; the footer is otherwise every page's. A
 * footer without a switch elsewhere (guest, error) keeps the mark at the right, as its board has. */
@media (min-width: 48rem) {
    .sitefoot__inner.sitefoot__inner--centred:not(:has(> .language)) > .page__operator {
        grid-column: 2;
        justify-self: center;
    }
}

/* === FIND YOUR TEAM, AND WHO HAS ASKED TO JOIN (Novo test feedback, 29/9) =======================
 * The results on /team/find and the request sent are drawn as the invitation card is (.noteam,
 * .invites): a state to act on, on the tint, one row per team with its one button. A result's
 * second line is the team's placement and size, muted, as a caption. (The search card that sat on
 * "Create your team" is gone: Kenneth's test, 4/10.) */
.gatecard .teamfind__notice {
    margin-top: var(--space-lg);
}

.teamfind__name {
    margin: 0;
    font-weight: var(--font-weight-bold);
    color: var(--colour-text);
}

.teamfind__meta {
    margin: 2px 0 10px;
    font-size: var(--font-size-sm);
    color: var(--colour-text-muted);
}

.teamfind__empty,
.teamfind__more {
    margin: var(--space-md) 0 0;
    color: var(--colour-text-muted);
}

.teamfind__note {
    margin: 4px 0 0;
}

.gatecard .teamfind__ask {
    margin-top: 0;
}

@container (min-width: 480px) {
    .teamfind__meta {
        margin-bottom: 0;
    }
}

/* The captain's panel: a name with its initials mark, then Approve and a quieter Decline. Same
 * rule between rows as the invitation list, and both buttons keep the 44px target. */
.requests {
    margin: 12px 0 0;
    padding: 0;
    list-style: none;
}

.requests__row + .requests__row {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--colour-rule-warm);
}

.requests__name {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 10px;
    font-weight: var(--font-weight-bold);
}

.requests__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.requests__actions .button {
    width: auto;
    margin: 0;
    padding: 0 20px;
}

/* 44px only where the pointer is not a thumb: on a phone the variants keep their 52 and 48
 * (the button contract's floor), as every other phone button does (design review). */
@media (min-width: 40rem) {
    .requests__actions .button {
        min-height: 44px;
    }
}

/* --- Mine skridt: when a save counts, and the first-save dialog ------------------------------
 *
 * Novo test feedback (2026-09-29): a tester saved, saw nought in the standings and believed the
 * save had failed. The saved band (the success band above) now carries a second line under its
 * sentence for today's save, and a participant's very first save opens a dialog once.
 */
.status__detail {
    margin: 2px 0 0;
    font-size: 15px;
    line-height: 1.4;
}

/* THE SCRIM OF A MODAL DIALOG (advisor 2026-10-04 21:40): Lasting Blue at 40 % over the page, so a
 * pop-up reads as a pop-up and the page behind it as inert but still there. The one overlay the
 * design contract allows ("a modal <dialog>'s backdrop"); every <dialog> opened with showModal()
 * takes it, so the product has one modal convention. A confirmation PAGE draws no scrim: it is the
 * white page with the dialog's card (see "A CONFIRMATION IS DRAWN AS THE DIALOG'S CARD"). */
dialog::backdrop {
    background: color-mix(in srgb, var(--colour-primary) 40%, transparent);
}

/* Centred by showModal() itself; only the size and the corners are set here. */
.firstsave {
    width: min(420px, calc(100vw - 2rem));
    /* The sheet's dialog (item 9), as the confirmation pages: 28 inside (it was 32; sweep 2, item 5). */
    padding: 28px;
    /* A visible edge, which forced-colours mode also keeps when it drops the shadow. */
    border: 1px solid var(--colour-rule-warm);
    border-radius: 24px;
    background: var(--colour-surface);
    color: var(--colour-text);
    box-shadow: var(--steps-today-lift);
    text-align: center;
}

/* A positive moment: the round Ice Blue check tile the other status moments carry, centred. */
.firstsave__tile {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    margin: 0 auto var(--space-sm);
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-primary);
}

.firstsave__tile .lineicon {
    width: 28px;
    height: 28px;
}

.firstsave__title {
    margin: 0 0 var(--space-2xs);
    font-size: 22px;
    line-height: 1.2;
    letter-spacing: -0.015em;
}

.firstsave__body {
    margin: 0 0 var(--space-md);
    font-size: 15px;
    color: var(--colour-text-muted);
    line-height: 1.5;
}

.firstsave form {
    margin: 0;
}

/* === RENAMING THE TEAM (Novo test feedback 28-29/9) ===========================================
 * A disclosure under the team's name in the hero, captain-only: the summary reads as the
 * placement card's "Change where the team counts" does (a bold quiet verb, 44px tall), and opened
 * it is one labelled field with its button beside it, wrapping under it on a narrow phone. */
.rename {
    margin-top: 8px;
}

.rename__summary {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    cursor: pointer;
}

.rename__summary:hover,
.rename__summary:focus-visible {
    text-decoration: underline;
    text-underline-offset: 3px;
}

.renameform {
    max-width: 36rem;
    margin-top: 8px;
}

.renameform__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}

/* The field is the item-12 box (48) beside the 56px button, the two centred on one line. */
.renameform__row .field__input {
    flex: 1 1 16rem;
    min-width: 0;
    min-height: 0;
}

.renameform__row .button {
    flex: 0 0 auto;
}

/* === WHO HAS ASKED TO JOIN, ABOVE THE ROSTER ON A PHONE (Kenneth, 30/9) ==========================
 * team/show.blade.php draws the panel twice: first in the main column, for a phone, and at the top
 * of the side column, for the two-column layout from 64rem. Exactly one is shown, so it is never
 * heard twice. (Where .teamwork--beside applies, the phone copy serves every width; see there.) */
.requests-panel--desk {
    display: none;
}

@media (min-width: 64rem) {
    .requests-panel--phone {
        display: none;
    }

    .requests-panel--desk {
        display: block;
    }
}

/* ==========================================================================================
 * DESIGN V4 — THE FOUNDATION (Novo, 2026-10-01)
 *
 * Novo (Line and Thomas) chose a conservative look on the 2026 Brand Book and CVI: a white ground,
 * Lasting Blue for text, buttons and the brand, Now Turquoise only on Lasting Blue, a 5% Lasting
 * Blue tint for bands and table heads, Ice Blue only in small round tiles. The approved pages are
 * kept in docs/design/proposals/2026-v4/; docs/task-briefs/design-v4-foundation.md is the brief.
 *
 * THIS LAYER IS THE SHELL AND THE SHARED PARTS ONLY: the two bars, the footers, the cards and the
 * figure band. The ground, the hairlines, the radius and the type changed in tokens.css, so most of
 * the product followed without a rule here. Each screen's own v4 task restyles its content.
 *
 * LAST IN THE FILE ON PURPOSE. Earlier layers set these same properties at the same weight, so a
 * rule here wins by coming last; where an earlier selector is heavier, this one repeats it rather
 * than raising the stakes with !important.
 * ========================================================================================== */

/* --- The bars: white, a hairline under the participant's, the footprints beside the name ------ */
.appbar,
.gatebar,
.gatebar--shared {
    background: var(--colour-surface);
}

.appbar {
    border-bottom-color: var(--colour-rule-warm);
}

/* THE BRAND: the mark and the name, two lines, 800. The tracked capitals of the 2026 boards are
 * gone; the name is set as the v4 pages set it. Every earlier wordmark rule is repeated here by its
 * own selector, because three of them outrank a bare `.gatemark` (see the 17px block above). */
.gatemark,
.gateshell .gatemark,
.appbar .gatemark,
.appbar .topbar .gatemark,
.gatebar--shared .gatemark,
.gatebar--shared:has(.gatebar__end) .gatemark,
.errorshell .gatemark {
    display: inline-flex;
    max-width: none;
    align-items: center;
    gap: 10px;
    margin: 0;
    color: var(--colour-text);
    font-size: 1.1875rem;
    font-weight: var(--font-weight-heavy);
    line-height: 1.05;
    letter-spacing: -0.01em;
    text-align: left;
    text-transform: none;
}

/* "Novo Step" over "Challenge": wide enough for "Novo Step" and too narrow for all three words, in
 * Arial and in the wider DejaVu Sans a Linux machine falls back to, so the string stays one string. */
.gatemark__name {
    max-width: 7em;
    white-space: normal;
}

.brandmark {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
}

.gatebar__brand:hover .gatemark {
    text-decoration: none;
}

.gatebar__brand:hover .gatemark__name {
    text-decoration: underline;
}

/* The phone bars set the mark smaller; the tracked 14px the signed-in phone bar used and the
 * guest bar's block-level cap at 320 were for the capitals, and are taken back here. */
@media (max-width: 47.99rem) {
    .gatemark,
    .gateshell .gatemark,
    .appbar .gatemark,
    .appbar .topbar .gatemark,
    .gatebar--shared .gatemark,
    .gatebar--shared:has(.gatebar__end) .gatemark,
    .gatebar--shared:has(.gatebar__end):has(.language) .gatemark,
    .errorshell .gatemark {
        display: inline-flex;
        max-width: none;
        font-size: 1rem;
        letter-spacing: -0.01em;
    }

    .brandmark {
        width: 28px;
        height: 28px;
    }
}

/* --- The footers: white, a hairline above, the Lasting Blue novohealth logo -------------------- */
.sitefoot,
.publicfoot {
    background: var(--colour-surface);
    color: var(--colour-text);
    border-top: var(--border-width) solid var(--colour-rule-warm);
}

.sitefoot .page__footer-brand,
.publicfoot .publicfoot__brand,
.sitefoot .page__operator,
.sitefoot .language,
.sitefoot .language__label,
.sitefoot .language__current,
.sitefoot .language__choice,
.sitefoot .language .link-button,
.publicfoot p,
.publicfoot .language__label,
.publicfoot .language__current,
.publicfoot .language__choice,
.publicfoot .link-button {
    color: var(--colour-text);
}

.sitefoot .language__label,
.publicfoot .language__label {
    color: var(--colour-text-muted);
}

/* The ring is ink again: the white ring the ink footers needed is invisible on white. */
.sitefoot :focus-visible,
.publicfoot :focus-visible {
    outline-color: var(--colour-focus);
}

/* THE FOOTER'S LANGUAGE PILL ON WHITE. It was an outlined pill on ink with the current language
 * filled white; on the white footer that fill vanished and both words read alike. Now as the guest
 * bar's pill already draws it on white: the trough edged in the field edge (4.53:1, so it bounds the
 * control under 1.4.11), the current language filled ink with white words, the other plain ink. The
 * markup and the accessible names are unchanged (partials/language-switcher). */
.sitefoot .language__options {
    border-color: var(--colour-border-field);
}

.sitefoot .language__current {
    background: var(--colour-primary);
    color: var(--colour-text-on-primary);
}

.sitefoot .language__choice {
    color: var(--colour-text);
}

.sitefoot .language__choice:hover {
    background: var(--colour-surface-band);
}

/* --- Where the old warm ground was a contrast, not a ground -----------------------------------
 * Rules that painted --colour-surface-warm on purpose AGAINST a white card or page: a locked day,
 * the admin's grouped fields, and the mail list's hover and its static row. With that token white
 * the last three went white on white and lost their state; they take the v4 band tint, the quiet
 * surface v4 draws for exactly this. The locked day is not here: a later rule already paints it the
 * quiet ground, and the My steps v4 task restyles it. The first-save dialog's backdrop was here
 * too; every modal dialog now takes the one scrim (see dialog::backdrop). */
.adminshell .admin__group,
.maillist__item:hover,
.maillist__item--static {
    background: var(--colour-surface-band);
}

/* The footer's wordmark, set as the bar sets it: words at 800, untracked. */
.sitefoot .page__footer-brand,
.publicfoot .publicfoot__brand {
    font-weight: var(--font-weight-heavy);
    letter-spacing: -0.01em;
    text-transform: none;
}

/* --- Cards: white, a soft shadow, 20px round (the radius is --radius-2xl in tokens.css) --------
 * The shadow is --shadow-md, the system's existing soft shadow. The v4 pages draw a longer one
 * (0 18px 50px, Lasting Blue at 6%); a semantic token for it needs the protected token gate's
 * shadow allowlist widened, which is a Class C decision for Kenneth (docs/task-briefs/design-v4-foundation.md).
 * The landing and sign-in column is not a card: it is the page's own text on the ground, without
 * an edge, and a shadow there drew a box nobody asked for. */
.panel,
.roster-panel,
.board-panel,
.details-panel,
.competition,
.gatecard:not(.gatecard--landing),
.gate,
.message,
.datepanel,
.confirm,
.noteam,
.decision,
.summarycard,
.matindex,
.matblock,
.card {
    box-shadow: var(--shadow-md);
}

/* --- The blue figure band (partials/figure-band.blade.php) ------------------------------------- */
.figband {
    border-radius: var(--radius-band);
    padding: var(--space-md) 30px;
    background: var(--colour-surface-ink);
    color: var(--colour-text-inverse);
}

.figband__figures {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    gap: var(--space-md);
    margin: 0;
    padding: 0;
    list-style: none;
}

.figband__figure {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
}

.figband__tile {
    display: grid;
    flex: 0 0 48px;
    place-items: center;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--colour-surface-ink-raised);
    color: var(--colour-accent-on-primary);
}

.figband__tile .lineicon {
    width: 24px;
    height: 24px;
}

.figband__pair {
    display: flex;
    flex-direction: column;
    min-width: 0;
    margin: 0;
}

.figband__label {
    color: var(--colour-text-on-primary-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.figband__value {
    font-size: 1.875rem;
    font-weight: var(--font-weight-heavy);
    line-height: 1.05;
    overflow-wrap: anywhere;
}

.figband__of {
    color: var(--colour-text-on-primary-muted);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
}

/* One small line under a figure's value (partials/figure-band's `detail`). */
.figband__detail {
    color: var(--colour-text-on-primary-muted);
    font-size: 15px;
    font-weight: var(--font-weight-regular);
}

.figband__note {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    margin: var(--space-sm) 0 0;
    padding-top: 14px;
    border-top: var(--border-width) solid var(--colour-rule-on-primary);
    color: var(--colour-text-on-primary-muted);
    font-size: var(--font-size-sm);
}

.figband__note::before {
    content: "";
    flex: 0 0 10px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--colour-accent-on-primary);
}

@media (max-width: 47.99rem) {
    .figband {
        padding: 20px;
    }

    .figband__figures {
        grid-template-columns: 1fr 1fr;
        gap: var(--space-sm);
    }

    .figband__tile {
        display: none;
    }

    .figband__value {
        font-size: 1.5rem;
    }
}

/* The converter's qualifier before an activity is chosen: disabled, on the v4 band tint rather
 * than the warm closed ground (the v4 journey walk, 2/10). */
.steps-page .converter .field__select:disabled {
    background-color: var(--colour-surface-band);
}

/* --- The days ------------------------------------------------------------------------------ */

.days {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-md);
    min-width: 0;
    /* A save returns to #indtast-skridt; the band saying what was saved sits just above, and must
     * stay in view (a tester once took a save for a failure). */
    scroll-margin-top: 8rem;
}

/* The two cards take the v4 hairline every other page's cards have, not the shell's darker
 * default edge (the v4 journey walk, 2/10). */
.card.days__card,
.card.daycard {
    border-color: var(--colour-rule-warm);
}

/* A phone first: the strip and one card. The computer's form appears from 48rem. */
.days__card--desk {
    display: none;
}

.dayphone {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-sm);
    min-width: 0;
}

/* A refusal's link has a twin per layout, because the refused box has a different id in each: the
 * computer's tile and the phone's card. Each twin is shown only where its box is. */
.status__link--desk {
    display: none;
}

@media (min-width: 48rem) {
    .days__card--desk {
        display: grid;
        gap: var(--space-md);
    }

    .dayphone,
    .status__link--phone {
        display: none;
    }

    .status__link--desk {
        display: inline;
    }
}

.days__head {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-end;
    gap: var(--space-sm);
}

.days__title {
    margin: 0;
    font-size: var(--font-size-xl);
}

.days__legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    margin: 0;
    padding: 0;
    list-style: none;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.mark--saved {
    color: var(--colour-success);
    font-weight: var(--font-weight-bold);
}

.mark--missing {
    display: inline-block;
    width: 11px;
    height: 11px;
    border-radius: 50%;
    background: var(--colour-danger);
    vertical-align: -1px;
}

.mark--unsaved {
    font-weight: var(--font-weight-bold);
}

.week {
    display: grid;
    gap: var(--space-2xs);
}

.week__title {
    margin: 4px 0 0;
    font-size: var(--font-size-base);
}

.week__range {
    margin-left: 8px;
    color: var(--colour-text-muted);
    font-weight: var(--font-weight-regular);
}

.week__row {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* A tile keeps one size in every state: a state change swaps a border style and a ground, never
 * a border width that would move the boxes (the 3px today ring and the 2px dashed edit are drawn
 * as an inset outline instead). */
.dtile {
    display: grid;
    align-content: start;
    gap: 6px;
    padding: 10px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 16px;
    background: var(--colour-surface);
}

.dtile--missing {
    box-shadow: inset 0 4px 0 var(--colour-danger);
}

.dtile--is-today {
    outline: 3px solid var(--colour-primary);
    outline-offset: -3px;
    background: var(--colour-surface-band);
}

.dtile.is-unsaved,
.daycard.is-unsaved {
    outline: 2px dashed var(--colour-primary);
    outline-offset: -2px;
    background: var(--colour-surface-band);
}

.dtile--future {
    border-style: dashed;
    /* The v4 cool ground, not the warm closed one (steps.html draws the days not yet reached cool). */
    background: var(--colour-surface-band);
    color: var(--colour-text-muted);
}

.dtile__when {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin: 0;
}

.dtile__when span {
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
}

.dtile__status {
    min-height: 18px;
    margin: 0;
    font-size: 12px;
    font-weight: var(--font-weight-bold);
}

.dtile--saved:not(.is-unsaved) .dtile__status::before {
    content: "✓ ";
    content: "✓ " / "";
    color: var(--colour-success);
}

.dtile--missing:not(.is-unsaved) .dtile__status::before {
    content: "";
    display: inline-block;
    width: 10px;
    height: 10px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--colour-danger);
}

.is-unsaved .dtile__status::before {
    content: "✎ ";
    content: "✎ " / "";
}

.dtile__label {
    font-size: 12px;
    font-weight: var(--font-weight-bold);
}

.dtile__input,
.daycard__input {
    width: 100%;
    border: 1px solid var(--colour-border-field);
    background: var(--colour-surface);
    color: var(--colour-text);
    font-family: inherit;
    font-weight: var(--font-weight-bold);
    text-align: right;
}

.dtile__input {
    height: 42px;
    padding: 0 10px;
    border-radius: 10px;
    font-size: 17px;
}

.dtile__input:focus-visible,
.daycard__input:focus-visible {
    outline: 3px solid var(--colour-focus);
    outline-offset: 2px;
}

.dtile__total,
.daycard__total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin: 0;
    background: var(--colour-surface-band);
    font-weight: var(--font-weight-bold);
}

.dtile__total {
    padding: 6px 8px;
    border-radius: 8px;
    font-size: 12px;
}

.dtile__total b {
    font-size: var(--font-size-base);
    font-variant-numeric: tabular-nums;
}

.dtile__error {
    margin: 0;
    padding-left: 6px;
    border-left: 3px solid var(--colour-danger);
    font-size: 12px;
}

.dtile__later,
.daycard__later {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
}

.days__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
}

.days__pending {
    margin: 0;
    font-weight: var(--font-weight-bold);
}

/* --- A phone: the strip, and one day's card ------------------------------------------------ */

.daystrip__list {
    display: flex;
    gap: 8px;
    margin: 0 -16px;
    padding: 4px 16px 8px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    list-style: none;
}

.daystrip__list::-webkit-scrollbar {
    display: none;
}

.daystrip__list > li {
    flex: 0 0 60px;
    scroll-snap-align: center;
}

/* position: relative keeps the chip's visually-hidden words inside the scrolling strip: an
 * absolutely positioned span otherwise escapes the scroll container and widens the page. */
.daychip {
    position: relative;
    display: grid;
    place-items: center;
    gap: 2px;
    min-height: 80px;
    padding: 8px 2px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 16px;
    background: var(--colour-surface);
    color: var(--colour-text);
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    text-decoration: none;
}

.daychip b {
    font-size: 20px;
}

.daychip__mark {
    min-height: 12px;
    font-size: 12px;
    line-height: 1;
}

.daychip--missing {
    box-shadow: inset 0 3px 0 var(--colour-danger);
}

.daychip--missing .daychip__mark {
    color: var(--colour-danger);
}

.daychip--saved .daychip__mark {
    color: var(--colour-success);
}

.daychip--future {
    border-style: dashed;
    background: var(--colour-surface-band);
    color: var(--colour-text-muted);
}

.daychip.is-unsaved {
    outline: 2px dashed var(--colour-primary);
    outline-offset: -2px;
    background: var(--colour-surface-band);
}

.daychip[aria-current="true"] {
    border-color: var(--colour-primary);
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
}

.daychip[aria-current="true"] .daychip__mark {
    color: var(--colour-text-inverse);
}

.daycard {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
}

.daycard__status {
    margin: 0;
}

.daycard__title {
    margin: 0;
    font-size: var(--font-size-xl);
}

.daycard__label {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

.daycard__input {
    height: 58px;
    padding: 0 14px;
    border-radius: 12px;
    font-size: 24px;
}

.daycard__total {
    align-items: center;
    padding: 12px 14px;
    border-radius: 12px;
}

.daycard__total b {
    font-size: 24px;
    font-variant-numeric: tabular-nums;
}

.daycard__later {
    padding: 28px 0;
    text-align: center;
}

/* SAVE ABOVE THE FOLD ON A PHONE (the main action, advisor 1/10). A smaller line and a tighter
 * card bring it up under the head's stat cards. */
@media (max-width: 47.9375rem) {
    .daycard {
        gap: 8px;
        padding: var(--space-sm);
    }

    /* The sheet's field, 48 with 12 corners (item 12; the last polish, 2026-10-05 21:00). */
    .daycard__input {
        height: 48px;
    }

    .daycard__total {
        padding: 8px 14px;
    }
}

/* --- The calculator: the band tint, one row, the figure ------------------------------------ */

.steps-page .converter {
    display: grid;
    gap: 14px;
    margin: 0;
    padding: var(--space-md);
    border: 0;
    border-radius: 24px;
    background: var(--colour-surface-band);
    box-shadow: none;
}

.steps-page .converter__title {
    margin: 0;
    font-size: var(--font-size-xl);
}

.steps-page .converter__hint {
    margin: 0;
    color: var(--colour-text-muted);
}

.steps-page .converter[data-live] .converter__calc {
    display: none;
}

/* --- The saved band: Lasting Blue with a turquoise tick, as the page draws it ---------------- */

.steps-page .status--success {
    padding: 14px 18px;
    border: 0;
    border-radius: 18px;
    background: var(--colour-surface-ink);
    color: var(--colour-text-inverse);
}

.steps-page .status--success .status__title,
.steps-page .status--success .status__detail {
    color: var(--colour-text-inverse);
}

.steps-page .status--success .status__mark {
    /* The ink band's own tick: Now Turquoise straight on Lasting Blue, no tile (Now Turquoise is only
     * ever used on Lasting Blue; on the shared done tile's Ice Blue it would vanish). */
    width: auto;
    height: auto;
    padding: 0;
    border-radius: 0;
    background: none;
    color: var(--colour-accent-on-primary);
}

/* ==========================================================================================
 * DESIGN V4 — MY TEAM (Novo, 2026-10-01; docs/task-briefs/design-v4-team.md)
 *
 * The approved page (docs/design/proposals/2026-v4/team.html) on the v4 foundation above: the
 * team name with "Rename" beside it and one small Ice Blue trail; the blue figure band (Captain,
 * Members, Team total, Place); the roster as the main card; to its right, who is asking to join,
 * the invitation, the sign-up deadline on the band tint and "Where the team counts" folded.
 * Every rule is scoped to the team page's own classes, so no other screen moves.
 * ========================================================================================== */

/* --- The page head: the name, Rename beside it, the trail at the far edge -------------------- */

.pagehead--team .rename {
    margin: 0;
}

.pagehead--team .rename__summary {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    color: var(--colour-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.pagehead--team .rename__summary .lineicon {
    width: 16px;
    height: 16px;
}

.pagehead--team .rename[open] {
    flex-basis: 100%;
}

.trail {
    flex: none;
    width: 340px;
    height: 96px;
    color: var(--colour-surface-tile);
}

@media (max-width: 56.24rem) {
    .trail {
        display: none;
    }
}

/* --- The band: the captain's name is wider than a figure and set smaller -------------------- */
.figband--team {
    margin: 0;
}

@media (min-width: 62.5rem) {
    .figband--team .figband__figures {
        grid-template-columns: 1.4fr 1fr 1fr 1fr;
        align-items: center;
    }
}

@media (min-width: 48rem) and (max-width: 62.49rem) {
    .figband--team .figband__figures {
        grid-template-columns: 1fr 1fr;
    }
}

.figband__figure--name .figband__value {
    font-size: var(--font-size-xl);
}

/* --- Card headings: an Ice Blue tile beside the words, and a count where there is one -------- */
.teamwork .panel__title,
.place-change__summary,
.diplomas__title {
    display: flex;
    align-items: center;
    gap: 12px;
}

.htile {
    display: inline-grid;
    flex: 0 0 40px;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-text);
}

.htile .lineicon {
    width: 20px;
    height: 20px;
}

.countbadge {
    padding: 2px 10px;
    border-radius: var(--radius-pill);
    background: var(--colour-surface-band);
    color: var(--colour-text);
    font-size: var(--font-size-xs);
    font-weight: 800;
}

/* --- The roster: its head on the band tint --------------------------------------------------- */
.roster-panel .roster-table:not(.roster-table--invites) thead th {
    padding-top: 10px;
    padding-bottom: 10px;
    background: var(--colour-surface-band);
}

.roster-panel .roster-table:not(.roster-table--invites) thead th:first-child {
    border-radius: 10px 0 0 10px;
}

.roster-panel .roster-table:not(.roster-table--invites) thead th:last-child {
    border-radius: 0 10px 10px 0;
}

/* --- The invitation: "or share the team link" as a divider ----------------------------------- */
.invite-panel .invite__alt {
    border-top: 0;
}

.invite-panel .invite__alt-heading {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.invite-panel .invite__alt-heading::before,
.invite-panel .invite__alt-heading::after {
    content: "";
    flex: 1;
    height: var(--border-width);
    background: var(--colour-rule-warm);
}

/* --- The deadline: a band on the tint, not an ink card --------------------------------------- */
.teamwork .deadline-panel {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 16px 18px;
    border: 0;
    border-radius: 18px;
    background: var(--colour-surface-band);
    box-shadow: none;
    color: var(--colour-text);
}

.teamwork .deadline-panel .deadline-panel__date,
.teamwork .deadline-panel .deadline-panel__time {
    color: var(--colour-text);
}

.teamwork .deadline-panel .deadline-panel__note {
    color: var(--colour-text-muted);
}

/* --- Where the team counts: folded, the heading is the summary ------------------------------- */
.place-panel .place-change {
    margin: 0;
}

.place-panel .place-change__summary {
    justify-content: space-between;
    min-height: 44px;
    cursor: pointer;
    font-size: var(--font-size-lg);
    font-weight: 800;
    list-style: none;
}

.place-panel .place-change__summary::-webkit-details-marker {
    display: none;
}

.place-panel .place-change__summary > span:last-child {
    flex: 1;
}

.place-panel .place-change__summary::after {
    /* Empty alternative text: the disclosure announces open and closed itself. */
    content: "+" / "";
    font-size: 1.5rem;
    line-height: 1;
}

.place-panel .place-change[open] > .place-change__summary::after {
    content: "\2013" / "";
}

.place-panel .place-change[open] > .place-change__summary {
    margin-bottom: var(--space-sm);
}

/* ==========================================================================================
 * DESIGN V4 — STANDINGS (Novo, 2026-10-01; docs/task-briefs/design-v4-standings.md)
 *
 * The approved page (docs/design/proposals/2026-v4/standings.html, as corrected 2026-10-01 17:20):
 * the title with what kind of numbers these are as a chip and one line under it; the blue band
 * with where the reader's team stands; the board's tabs and filters on one row; the board as one
 * card. No individual ranking anywhere (Novo 22/9).
 * ========================================================================================== */
.statechip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: var(--chip-padding);
    border-radius: var(--radius-pill);
    background: var(--colour-surface-band);
    color: var(--colour-text);
    font-size: var(--font-size-chip);
    font-weight: var(--font-weight-bold);
}

.statechip__dot {
    flex: 0 0 var(--chip-dot);
    width: var(--chip-dot);
    height: var(--chip-dot);
    border-radius: 50%;
    background: var(--colour-text);
}

.statechip--final .statechip__dot {
    background: var(--colour-text);
}

.standings-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
}

/* Below 64rem the tabs and the filters stack, each starting at the left edge (the filters are
 * the selects of the target block at the end of this file). */
@media (max-width: 63.999rem) {
    .standings-controls {
        flex-direction: column;
        align-items: flex-start;
    }
}

/* ==========================================================================================
 * DESIGN V4 — THE FRONT PAGE (docs/task-briefs/design-v4-front.md)
 *
 * The approved page is docs/design/proposals/2026-v4/index.html; the measures below are its own.
 * The page renders through layouts/gate's `page` section, so none of the gate card's rules reach it,
 * and every class here is the front page's own (front__*, doors, door); the old landing's rules for
 * those names were removed when these replaced them.
 * ========================================================================================== */
.frontpage {
    display: block;
}

.front__hero,
.front__band,
.front__inner {
    width: 100%;
    max-width: 77.5rem;
    margin-inline: auto;
    padding-inline: 16px;
}

.front__eyebrow {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-heavy);
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
}

.front__title {
    margin: 14px 0 18px;
    font-size: clamp(2.25rem, 1.4rem + 3vw, 3.625rem);
    font-weight: var(--font-weight-heavy);
    line-height: 1.02;
    letter-spacing: -0.02em;
    text-wrap: balance;
}

.front__lede {
    max-width: 36ch;
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-lg);
    line-height: 1.45;
}

/* The facts as one quiet line under the lede (advisor 5/10 07:20), not pills. */
.front__facts {
    margin: 12px 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: 1.45;
}

.front__hero {
    display: grid;
    grid-template-areas: "intro" "entry" "photo";
    gap: 16px;
    padding-block: 16px 0;
}

.front__intro {
    grid-area: intro;
}

.front__photo {
    grid-area: photo;
}

.front__entry {
    grid-area: entry;
}

.front__photo {
    position: relative;
    margin: 0;
}

/* The file is already cut free of the names in its corner; the crop here is only composition. */
.front__photo img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    object-position: 50% 30%;
    border-radius: 28px 28px 28px 80px;
}

.front__live {
    position: absolute;
    left: 12px;
    bottom: 12px;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    border-radius: var(--radius-pill);
    background: var(--colour-surface-ink);
    color: var(--colour-text-inverse);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
}

.front__live::before {
    content: "";
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--colour-accent-on-primary);
}

/* --- The doors ------------------------------------------------------------------------------ */
.doors__list {
    display: grid;
    gap: 16px;
}

/* The sheet's card (item 10): a hairline, 20px corners, 20 inside on a phone and 24 from the tablet,
 * the soft lift. */
.door {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 20px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: 20px;
    background: var(--colour-surface);
    box-shadow: 0 10px 30px color-mix(in srgb, var(--colour-primary) 5%, transparent);
}

.door__head {
    display: flex;
    align-items: flex-start;
    gap: 12px;
}

.door__who {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: 0.75rem;
    font-weight: var(--font-weight-heavy);
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
}

.door__heading {
    margin: 4px 0 6px;
    font-size: var(--font-size-xl);
    /* Every card heading's 22/700 (sweep 2, item 3; advisor 2026-10-05 21:00). */
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.01em;
}

.door__line {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-base);
    line-height: 1.45;
}

.door__note {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

.door__note .lineicon {
    flex: 0 0 18px;
    width: 18px;
    height: 18px;
}

.door__field {
    display: grid;
    gap: 6px;
    margin-top: auto;
}

.door__label {
    font-size: 0.875rem;
    font-weight: var(--font-weight-bold);
}

.door .door__input {
    width: 100%;
}

/* The two doors are twins (audit 1006, D5): both buttons the form control's 48 under their 48 field.
 * One primary on the screen (item 4) is said by the captain door's fill; the join door is outlined. */
.door .door__go {
    width: 100%;
    min-height: var(--control-height);
    gap: 8px;
    font-size: var(--font-size-base);
}

.doors__already {
    margin: 16px 0 0;
    text-align: center;
    font-size: var(--font-size-base);
}

.doors__already small {
    display: block;
    margin-top: 4px;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.front__closed {
    max-width: 40rem;
}

/* --- The band, how it works, the materials --------------------------------------------------- */
/* The density table (4/10 23:30): sections 16 apart on a phone, 24 from the tablet. */
.front__band {
    margin-top: 16px;
}

.front__how {
    margin-top: 16px;
    padding-block: 24px;
    background: var(--colour-surface-band);
}

/* 28px: a landing page's section asks a little more than the sheet's 22px card heading (advisor
 * 5/10 07:20); every other page keeps 22. */
.front__h2 {
    margin: 6px 0 0;
    font-size: 1.75rem;
    line-height: 1.1;
    font-weight: var(--font-weight-heavy);
    letter-spacing: -0.01em;
}

.front__steps {
    display: grid;
    gap: 16px;
    margin: 16px 0 0;
    padding: 0;
    list-style: none;
}

/* Each step is the sheet's card (item 10) opening with its tile heading; the list's order is the
 * order, so no large numeral stands beside it. */
.front__step {
    display: grid;
    align-content: start;
    gap: 12px;
    padding: 20px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: 20px;
    background: var(--colour-surface);
    box-shadow: 0 10px 30px color-mix(in srgb, var(--colour-primary) 5%, transparent);
}

.front__step-head {
    display: flex;
    align-items: center;
    gap: 12px;
}

.front__step-heading {
    margin: 0;
    font-size: 1.375rem;
    font-weight: var(--font-weight-heavy);
    line-height: 1.2;
}

.front__step-body {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-base);
    line-height: 1.45;
}

.front__materials {
    padding-block: 16px 24px;
}

.front__materials-inner {
    display: grid;
    gap: 16px;
}

.front__materials-lede {
    margin: 8px 0 0;
    color: var(--colour-text-muted);
    line-height: 1.45;
}

.front__links {
    display: grid;
    gap: 12px;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Equal height in a row (item 11, 16:20): the grid stretches each item, and the card fills it. */
.front__links > li {
    display: flex;
}

.front__links .front__link {
    flex: 1 1 auto;
}

/* The sheet's stat card (item 2) as a link: a hairline, 16px corners, 14/16 inside, a 40px tile.
 * Not .figcard: that one steps its tile down to 32 on a phone, and these keep the sheet's 40. */
.front__link {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 76px;
    padding: 14px 16px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: 16px;
    color: var(--colour-text);
    font-weight: var(--font-weight-bold);
    text-decoration: none;
}

.front__link:hover {
    border-color: var(--colour-border-strong);
}

.front__link small {
    display: block;
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
}

.front__link-tile {
    display: grid;
    flex: 0 0 40px;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-text);
}

.front__link-tile .lineicon {
    width: 20px;
    height: 20px;
}

/* On a phone the three steps are one card holding a compact list (advisor 5/10 07:50): a row each,
 * the tile beside the bold word and its line, 56px a row, a hairline between. Three tall cards took
 * about 300px. From the tablet they are three cards again. */
@media (max-width: 47.99rem) {
    .front__steps {
        gap: 0;
        padding: 4px 16px;
        border: var(--border-width) solid var(--colour-rule-warm);
        border-radius: 20px;
        background: var(--colour-surface);
        box-shadow: 0 10px 30px color-mix(in srgb, var(--colour-primary) 5%, transparent);
    }

    .front__step {
        grid-template-columns: 40px minmax(0, 1fr);
        gap: 0 12px;
        align-items: center;
        padding: 8px 0;
        border: 0;
        border-radius: 0;
        background: none;
        box-shadow: none;
    }

    .front__step + .front__step {
        border-top: var(--border-width) solid var(--colour-rule-warm);
    }

    .front__step-head {
        display: contents;
    }

    .front__step .htile {
        grid-row: span 2;
    }

    .front__step-heading {
        font-size: 1rem;
    }

    .front__step-body {
        grid-column: 2;
        font-size: 0.875rem;
        line-height: 1.35;
    }
}

/* --- Wider screens: the photo beside the words, the doors overlapping its foot ---------------- */
@media (min-width: 48rem) {
    .front__hero,
    .front__band,
    .front__inner {
        padding-inline: 48px;
    }

    .doors__list {
        grid-template-columns: 1fr 1fr;
        gap: 24px;
    }

    .door,
    .front__step {
        padding: 24px;
    }

    .front__band,
    .front__how {
        margin-top: 24px;
    }

    .front__how {
        padding-block: 32px;
    }

    .front__materials {
        padding-block: 24px 32px;
    }

    .front__steps {
        grid-template-columns: repeat(3, 1fr);
        gap: 24px;
    }

    .front__links {
        grid-template-columns: repeat(3, 1fr);
    }
}

@media (min-width: 62.5rem) {
    .front__hero {
        grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
        grid-template-areas: "intro photo" "entry entry";
        gap: 0 48px;
        align-items: center;
        padding-block: 24px 0;
    }

    .front__intro {
        padding-bottom: 110px;
    }

    .front__photo img {
        aspect-ratio: 16 / 10;
        border-radius: 48px 0 0 160px;
    }

    .front__live {
        left: -22px;
        bottom: 120px;
        padding: 12px 18px;
        font-size: var(--font-size-sm);
    }

    /* The doors stand over the photograph's foot, as the approved page draws them. */
    .front__entry {
        position: relative;
        z-index: 1;
        margin-top: -84px;
    }

    /* Sign-ups closed: one field under the words, not a pair of cards, so nothing reaches over the
       photograph and the words need no room left under them for it. */
    .front__hero--closed .front__intro {
        padding-bottom: 0;
    }

    .front__hero--closed .front__entry {
        margin-top: 32px;
    }

    .front__materials-inner {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr);
        align-items: center;
        gap: 24px;
    }
}

/* --- The figure band's status line and progress (partials/figure-band) ----------------------- */
.figband__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px 20px;
    margin-bottom: 22px;
}

.figband__status {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin: 0;
    color: var(--colour-accent-on-primary);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-heavy);
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
}

.figband__status::before {
    content: "";
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--colour-accent-on-primary);
}

.figband__progress {
    display: grid;
    flex: 1 1 260px;
    gap: 6px;
    max-width: 420px;
}

.figband__position {
    margin: 0;
    font-size: var(--font-size-sm);
}

.figband__bar {
    display: flex;
    gap: 3px;
}

.figband__seg {
    flex: 1 1 0;
    height: 8px;
    border-radius: var(--radius-pill);
    background: var(--colour-rule-on-primary);
}

.figband__seg--done {
    background: var(--colour-accent-on-primary);
}

/* --- The front page's band at the sheet's sizes (advisor 5/10 07:20): it stays the ink band, with
 * the stat row's 40px tile, 24px values and labels in sentence case. The other screens' bands are
 * theirs (/sign-in has none since 2026-10-06). */
.front__band .figband__tile {
    flex-basis: 40px;
    width: 40px;
    height: 40px;
}

.front__band .figband__tile .lineicon {
    width: 20px;
    height: 20px;
}

.front__band .figband__figure {
    gap: 12px;
}

.front__band .figband__label {
    letter-spacing: normal;
    text-transform: none;
}

.front__band .figband__value {
    font-size: 1.5rem;
}

/* --- Field errors on the front page: above the field, 14px bold in ink, led by the sheet's "!"
 * mark (item 3) so position is not all that says it (advisor 5/10 07:20). No new red: the mark's
 * ground is the status card's own Lava Red. Scoped to the landing's entry (both doors and the
 * closed form), not .frontpage: layouts/gate renders /sign-in in main.frontpage too (every page with
 * a `page` section). /sign-in's form shares the disc through the selector lists below. */
.front__entry .field__error {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.875rem;
    font-weight: var(--font-weight-bold);
    color: var(--colour-text);
}

.front__entry .field__error::before,
.gatecard--signin .gate__form .field__error::before,
.gateshell--sheet .gate__form .field__error::before {
    display: grid;
    flex: 0 0 20px;
    place-items: center;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--colour-danger);
    color: var(--colour-text-inverse);
    font-size: 13px;
    font-weight: var(--font-weight-heavy);
    line-height: 1;
    content: "!" / "";
}

@media (forced-colors: active) {
    .front__entry .field__error::before,
    .gatecard--signin .gate__form .field__error::before,
    .gateshell--sheet .gate__form .field__error::before {
        border: 1px solid CanvasText;
    }
}

/* The throttle notice (item 3) stands above the doors with the sections' gap under it. */
.front__entry .throttle-notice {
    margin: 0 0 16px;
}

/* The closed state's one field and action keep the row the landing card gave them (that rule is
 * scoped to .gatecard--landing, which the v4 page no longer renders). */
.front__closed .gate__entry-submit {
    flex: 0 0 auto;
    width: auto;
    min-width: 0;
    gap: 10px;
    padding: 0 32px;
}

.front__closed .gate__hint {
    margin: 14px 0 0;
    font-size: 15px;
    color: var(--colour-text-muted);
}

/* ==========================================================================================
 * DESIGN V4 — COMPETITIONS (Novo, 2026-10-01; docs/task-briefs/design-v4-competitions.md)
 *
 * The approved page (competitions.html): the head with the team's readiness as a chip under the
 * title and one small Ice Blue trail; four cards, each a round Ice Blue tile with the state chip
 * opposite it, the name, the rule and the facts as short chips; and where the winners are
 * announced as the ink band with one turquoise button. Scoped to .competitions-v4, so no other
 * screen moves and the earlier competition rules above are overridden rather than edited.
 * ========================================================================================== */

/* --- The head: the readiness chip under the title, the trail at the far edge ----------------- */

.competitions-v4 .teamrow {
    margin-top: var(--space-xs);
}

/* A team the published result has no row for: a fact, on the v4 band tint (the warm grounds went). */
.competitions-v4 .teamrow--neutral {
    background: var(--colour-surface-band);
    color: var(--colour-text);
}

/* Ready, and the neutral fact, are the status chip (the system values layer at the end of this file:
 * a tint pill, an 8px dot). The other states keep their band, because they carry a count and the way
 * onward. */
.competitions-v4 .teamrow--ready {
    display: inline-flex;
    padding: 8px 14px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: var(--radius-pill);
    background: var(--colour-surface);
    color: var(--colour-text);
}

.competitions-v4 .teamrow--ready .teamrow__dot {
    display: inline-grid;
    place-items: center;
    width: 18px;
    height: 18px;
}

.competitions-v4 .teamrow--ready .teamrow__dot::before {
    content: "✓";
    content: "✓" / "";
    color: var(--colour-text-inverse);
    font-size: 11px;
    line-height: 1;
}

/* --- The cards: two across from the tablet up, one on a phone --------------------------------- */
.competitions-v4 .competition-list {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-md);
}

@media (min-width: 56.25rem) {
    .competitions-v4 .competition-list {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* The sheet's card head (item 3, 2026-10-05 16:20): the 40px tile beside the 22 heading, the state chip
 * at the row's end (under the heading on a phone), the rest of the body under them at full width. The
 * body's box steps aside (display: contents, a plain div) so its heading can share the tile's row. The
 * state stays last in the markup (the name is read first); only its place on the screen moves up. */
.competitions-v4 .competition {
    container-type: inline-size;
    display: grid;
    grid-template-columns: 40px minmax(0, 1fr) auto;
    grid-template-areas: none;
    align-items: center;
    align-content: start;
    gap: 0 12px;
    height: 100%;
    padding: 26px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: var(--radius-2xl);
    background: var(--colour-surface);
    box-shadow: var(--shadow-md);
}

.competitions-v4 .competition__icon {
    grid-area: auto;
    grid-row: 1;
    grid-column: 1;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-text);
}

.competitions-v4 .competition__icon svg {
    width: 20px;
    height: 20px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.competitions-v4 .competition__body {
    display: contents;
}

.competitions-v4 .competition__body > * {
    grid-column: 1 / -1;
}

.competitions-v4 .competition__body > .competition__name {
    grid-row: 1;
    grid-column: 2;
    margin: 0;
    font-size: var(--font-size-xl);
    line-height: 1.2;
}

.competitions-v4 .competition__rule {
    margin-top: var(--space-2xs);
}

.competitions-v4 .competition__meta {
    grid-area: auto;
    grid-row: 1;
    grid-column: 3;
    justify-self: end;
    width: auto;
    margin: 0;
    padding: 0;
    border: 0;
}

/* In a narrow card - a phone, or two across near 900px - the chip goes under the heading, so a long
 * name keeps the row. By the card's own width (a container query), not the viewport's. */
@container (max-width: 34rem) {
    .competitions-v4 .competition__meta {
        grid-row: 2;
        grid-column: 1 / -1;
        justify-self: start;
        margin-top: 12px;
    }
}

/* The state chip is the one status chip (sweep 2, item 10; advisor 2026-10-05 21:00), drawn by the
 * system values layer at the end of this file; here only the <dd>'s own indent goes. */
.competitions-v4 .competition__state {
    margin: 0;
}

/* EXACTLY TWO FACT TILES OF EQUAL WIDTH on every card (the advisor's brief, 2026-10-04 10:00, and
 * competitions.html): a two-column grid on the band tint, so the four cards share one anatomy. */
.competitions-v4 .competition__facts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    margin: var(--space-sm) 0 0;
    padding: 0;
    border: 0;
}

.competitions-v4 .competition__fact,
.competitions-v4 .competition__fact:first-child {
    min-width: 0;
    padding: 10px 14px;
    border: 0;
    border-radius: var(--radius-xl);
    background: var(--colour-surface-band);
}

.competitions-v4 .competition__fact-label {
    font-size: var(--font-size-base);
}

.competitions-v4 .competition__fact-detail {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-xs);
    line-height: 1.35;
}

/* A ONE-LINE DISCLOSURE UNDER THE TILES (Best Team Name's three criteria; the advisor, 2026-10-04 16:20):
 * a quiet summary with the "+" / en dash the other disclosures draw, the detail as one muted line. */
.competition__more {
    margin-top: 10px;
}

.competition__more-summary {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: var(--touch-target-min);
    color: var(--colour-primary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    cursor: pointer;
    list-style: none;
}

.competition__more-summary::-webkit-details-marker {
    display: none;
}

.competition__more-summary::after {
    content: "+" / "";
    font-size: 1.25rem;
    line-height: 1;
}

.competition__more[open] > .competition__more-summary::after {
    content: "\2013" / "";
}

.competition__more-summary:hover,
.competition__more-summary:focus-visible {
    text-decoration: underline;
}

.competition__more-body {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* --- The diploma: a light card under the band (competitions.html) ------------------------------
 * The round Ice Blue tile, the title and one line, and the two diplomas at the far end; on a phone
 * the buttons drop under the words. Shown only after publication, to somebody in the result. */
.diplomacard {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px 20px;
    padding: 22px 26px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: var(--radius-2xl);
    background: var(--colour-surface);
}

.diplomacard__tile {
    display: grid;
    flex: none;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-primary);
}

.diplomacard__tile .lineicon {
    width: 20px;
    height: 20px;
}

.diplomacard__text {
    flex: 1 1 240px;
    min-width: 0;
}

/* Every card heading's 22 beside the 40 tile (sweep 2, item 1; advisor 2026-10-05 21:00). */
.diplomacard__title {
    margin: 0;
    font-size: var(--font-size-xl);
}

.diplomacard__line {
    margin: 2px 0 0;
    color: var(--colour-text-muted);
}

.diplomacard__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 0;
}

/* --- Where the winners are announced: the ink band, one turquoise button --------------------- */
.winnersband {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    padding: 22px 26px;
    border-radius: var(--radius-2xl);
    background: var(--colour-surface-ink);
    color: var(--colour-text-inverse);
}

.winnersband__text {
    margin: 0;
}

.winnersband__title {
    display: block;
    font-size: 17px;
}

.winnersband__detail {
    display: block;
    margin-top: 2px;
    color: var(--colour-text-on-primary-muted);
    font-size: var(--font-size-sm);
}

.winnersband__open {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 20px;
    border-radius: var(--radius-pill);
    background: var(--colour-accent-on-primary);
    color: var(--colour-surface-ink);
    font-weight: var(--font-weight-bold);
    text-decoration: none;
}

.winnersband__open:focus-visible {
    outline-color: var(--colour-accent-on-primary);
}

/* --- The gate family in v4: the small mark in Ice Blue, round Ice Blue icon tiles -------------
 * "One small trail per page at most, in Ice Blue" and "Ice Blue only for small round icon tiles"
 * (design v4 shared rules). The mark is inline (partials/footprints-mark), so it takes the colour. */
.gateprints {
    color: var(--colour-surface-tile);
}

.gatecard__icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--colour-surface-tile);
}

/* THE STATE CHIP ON WHITE: a hairline pill with the coloured dot beside the word, as v4 draws a
 * status ("red and green only as small marks, always with their word"). The rose ground is gone;
 * the dot carries the colour and the word carries the meaning. The quiet chip (a deadline that
 * passed, not a failure) keeps its grey dot and its muted words. */
.gatecard__chip,
.gatecard__chip--quiet {
    border: var(--border-width) solid var(--colour-rule-warm);
    background: var(--colour-surface);
}

/* --- /sign-in in v4 (docs/task-briefs/design-v4-sign-in.md) -----------------------------------
 * One card, centred, and the campaign's one status line under it (2026-10-06; it was the front page's
 * band). The card is a real .gatecard--signin, so the field keeps its envelope and its stacked button
 * (the rules above); what is restated here is the card's own frame and the heading, which the gate
 * card's poster-size landing rules no longer set. */
/* The density table (4/10 23:30): 16 under the bar and 24 above the footer on a phone, 24 and 32 from
 * the tablet. */
.signin {
    width: 100%;
    max-width: 77.5rem;
    margin-inline: auto;
    padding: 16px 16px 24px;
}

/* 35rem, not the family's 400px card: a 40-character Novo address has to fit the field (#196's reason
 * for stacking the button). At the family rule's specificity, later. */
/* The sheet's card (item 10): a hairline, 20px corners, 20 inside on a phone and 24 from the tablet,
 * the soft lift. */
.gateshell .gatecard.signin__card {
    width: 100%;
    max-width: 35rem;
    margin: 0 auto;
    padding: 20px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: 20px;
    background: var(--colour-surface);
    box-shadow: 0 10px 30px color-mix(in srgb, var(--colour-primary) 5%, transparent);
}

/* A notice under the head and the form under that: the card's 16. */
.signin__card .status,
.signin__card .throttle-notice {
    margin: 16px 0 0;
}

/* The label 16 under the head and the sheet's 6 above its field (item 12). The focus ring is the
 * single band inside the box now (the 5/10 amendment), so the room the old ring took outside it is
 * not needed. At the specificity of the gate's own `.gatecard .gate__form > .gate__label`, one class
 * more. */
.gatecard.gatecard--signin .gate__form > .gate__label {
    margin: 16px 0 6px;
}

/* THE CAMPAIGN AS ONE QUIET LINE under the card, at the card's width and centred (Kenneth's finding,
 * 2026-10-06; it replaced the front page's band here): the head chip, 16 under the card, 24 from the
 * tablet. */
.signin__status {
    max-width: 35rem;
    margin: 16px auto 0;
    text-align: center;
}

@media (min-width: 48rem) {
    .signin {
        padding: 24px 48px 32px;
    }

    .gateshell .gatecard.signin__card {
        padding: 24px;
    }

    .signin__status {
        margin-top: 24px;
    }
}

/* --- My details, the last 5 % (the advisor's brief of 2026-10-04 10:00) -------------------------
 * The form is the main task: its card is the only raised one and now says what it is, with its
 * tile. The three side cards are flat — the v4 hairline, no shadow, 20px in, 16px apart. */
.profilework__aside {
    gap: 16px;
}

.profilework__aside .panel {
    padding: 20px;
    border: 1px solid var(--board-rule);
    box-shadow: none;
}

/* "Bekræftet": the word, with a green dot that only repeats it. */
.emailcard__verified {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 8px 0 0;
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    background: var(--board-positive-ground);
    color: var(--colour-text);
    font-size: 13px;
    font-weight: var(--font-weight-bold);
}

.emailcard__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--colour-success);
}

/* The way to the team: an outline button with its arrow, not a text link. */
.teamcard__open {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

/* What is stored: four lines, each after a check, as Support's "can help" list. */
.storedcard .storedcard__list {
    display: grid;
    gap: 8px;
}

.storedcard .storedcard__list .storedcard__item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 0;
    border-bottom: 0;
    font-size: 15px;
    line-height: var(--line-height-base);
}

.storedcard__item .lineicon {
    flex: none;
    width: 18px;
    height: 18px;
    margin-top: 3px;
    color: var(--colour-primary);
}

/* THE SAVED BAND, FLAT (the advisor, 2026-10-04 15:00: "band tint plus the check, no stripe"). v4 has no
 * side stripes; the confirmation stands on the band tint in Lasting Blue (13.5:1), and the check — Lasting
 * Blue in an Ice Blue tile (component sheet item 3), a mark beside the words, not the words — repeats
 * that something went right (WCAG 2.2 AA 1.4.1). My steps keeps its own ink band (.steps-page .status--success, more specific). The
 * other notices lost their edges too: their non-colour cue is the mark in "THE NOTICES IN v4". */
.status--success {
    gap: 12px;
    padding: 14px 16px;
    border-left: 0;
    border-radius: 16px;
    background: var(--colour-surface-band);
    color: var(--colour-text);
}

/* The done mark of the component sheet (item 3, "check = done"): the check in Lasting Blue in a 28px
 * Ice Blue tile (12.1:1), the same tile as every other notice's mark. */
.status--success .status__mark {
    box-sizing: border-box;
    width: 28px;
    height: 28px;
    padding: 5px;
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-primary);
}

@media (forced-colors: active) {
    .status--success .status__mark {
        border: 1px solid CanvasText;
    }
}

/* --- Support in v4 (docs/task-briefs/design-v4-support.md) -------------------------------------------
 * The light cards open with a round Ice Blue tile beside their eyebrow, as My team's and My details'
 * cards do (.htile): an envelope for getting in, footprints for steps and days, people for teams, a
 * wrench for what support can do. The ink panel takes none: Ice Blue stays on white. */
.panel__eyebrow--tiled {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* --- Support, the last 5 % (the advisor's brief of 2026-10-04 10:00) ----------------------------
 * Less "FAQ document": the questions fold, the contact box says one line and gives two rows, and
 * what support can help with is four checked items. The section cards stand 24px apart. */
.helpgrid__answers {
    gap: 24px;
}

/* ONE QUESTION, ONE ROW. The rows sit under each other with a hairline between them; the answer
 * opens under its question. The earlier spacing (a 24px gap and 24px of padding) was for answers
 * that were always open, and between folded rows it read as empty space. */
.helpqa {
    gap: 0;
}

.helpqa__item + .helpqa__item {
    padding-top: 0;
}

/* THE ROW IS THE TARGET: a flex summary, so no marker, at least 44px tall, the question taking the
 * free width so the mark sits at the far end. The mark is My team's (.place-change__summary): "+"
 * closed, an en dash open, silent to a screen reader because the
 * disclosure announces open and closed itself. */
.helpqa__summary {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: var(--touch-target-min);
    padding: 10px 0;
    cursor: pointer;
    list-style: none;
}

.helpqa__summary::-webkit-details-marker {
    display: none;
}

.helpqa__summary::after {
    flex: none;
    content: "+" / "";
    color: var(--colour-primary);
    font-size: 1.5rem;
    line-height: 1;
}

.helpqa__item[open] > .helpqa__summary::after {
    content: "\2013" / "";
}

.helpqa__summary .helpqa__q {
    flex: 1;
    font-size: 17px;
}

/* The underline goes under the words alone, as on the other two disclosures. */
.helpqa__summary:hover .helpqa__q,
.helpqa__summary:focus-visible .helpqa__q {
    text-decoration: underline;
}

/* 8px above the answer: the summary's focus ring reaches 6px below it (3px offset, 3px wide), and with no
 * gap it crossed the answer's first line. */
.helpqa__item .helpqa__a {
    margin: 8px 0 16px;
}

/* THE CONTACT BOX: one lede, then a row per route — its topic, three words on what it covers and a
 * chevron, opening a mail — with the address as plain text under it. The rule between the rows is
 * the ink panel's own. */
.helpcontact__block {
    display: grid;
    gap: 12px;
}

.helpcontact__lede {
    margin: 0 0 8px;
    color: var(--colour-text-on-primary);
    font-size: 16px;
    line-height: var(--line-height-base);
}

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

.helpcontact__route + .helpcontact__route {
    border-top: var(--border-width) solid var(--colour-rule-on-primary);
}

.helpcontact__row {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: var(--touch-target-min);
    padding: 12px 0 4px;
    color: var(--colour-text-on-primary);
    text-decoration: none;
}

.helpcontact__text {
    display: grid;
    flex: 1;
    gap: 2px;
}

.helpcontact__topic {
    font-size: 16px;
    font-weight: var(--font-weight-bold);
}

.helpcontact__about {
    color: var(--colour-text-on-primary-muted);
    font-size: 14px;
}

.helpcontact__row .lineicon {
    flex: none;
    width: 20px;
    height: 20px;
}

.helpcontact__row:hover .helpcontact__topic,
.helpcontact__row:focus-visible .helpcontact__topic {
    text-decoration: underline;
}

/* White, not the turquoise accent: it is text to copy, and the accent reads as a link on ink. */
.helpcontact__address {
    margin: 0 0 12px;
    color: var(--colour-text-on-primary);
    font-size: 14px;
    overflow-wrap: anywhere;
}

/* An unpublished route says so in the row's small line and has nothing under it. */
.helpcontact__row--off {
    padding-bottom: 12px;
}

.helpcontact__never {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: 14px;
}

/* WHAT SUPPORT CAN HELP WITH: four items, each after a check, and the one line on what it cannot. */
.helpcan__list {
    display: grid;
    gap: 10px;
    margin: 8px 0 0;
    padding: 0;
    list-style: none;
}

.helpcan__item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 16px;
    line-height: var(--line-height-base);
}

.helpcan__item .lineicon {
    flex: none;
    width: 20px;
    height: 20px;
    margin-top: 2px;
    color: var(--colour-primary);
}

.helpcan__cannot {
    margin: 16px 0 0;
    padding-top: 16px;
    border-top: var(--border-width) solid var(--colour-border-soft);
    color: var(--colour-text-muted);
    font-size: 15px;
}

/* ==========================================================================================
 * DESIGN V4 — CREATE AND FIND YOUR TEAM (Novo, 2026-10-02; docs/task-briefs/design-v4-team-entry.md)
 *
 * The two pages stand on the shared v4 gate (the round tile, the 400px card; b1, #332). What is
 * theirs alone: the panels inside the card — "Find your team" on Create, the request already sent
 * and a waiting invitation on both — sit flat on the band tint. They were cards inside a card, each with its own soft
 * shadow and the older field tint; v4 has one card and bands within it. Scoped to the onboarding
 * card, so the no-team card on My steps, which stands on the page ground, keeps its own look.
 * ========================================================================================== */
.gatecard--onboarding .noteam {
    border-radius: var(--radius-2xl);
    background: var(--colour-surface-band);
    box-shadow: none;
}

/* ==========================================================================================
 * THE SIGN-IN CODE ON "CHECK YOUR EMAIL" (2026-10-02; docs/task-briefs/sign-in-code.md)
 *
 * Page-level only, on the shared gate field and button (b1's): the six digits large, spaced and
 * in tabular figures so "482 913" reads as the mail draws it; the address sentence under the form,
 * where it now explains what was asked for rather than opening the card.
 * ========================================================================================== */
/* THE GATE'S ONE TREATMENT FOR SIX DIGITS: the administrators' code field (.gatecard--code .mfa__code),
 * so the two code fields on the gate shell look alike — 64 tall, 28 semibold, centred, tabular, the
 * code tracking five times over (and as much before the first digit, to keep the row centred). */
.gatecard--mail .checkemail__code-input {
    height: 64px;
    font-size: 28px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    text-align: center;
    letter-spacing: calc(var(--tracking-code) * 5);
    padding-inline: calc(var(--tracking-code) * 5) 0;
}

/* --- Clearing the staging campaign (Kenneth, 2026-10-04; admin/campaign-clear) ---------------------
 * The reset's table as the command prints it: what goes on the left, the count on the right, the
 * accounts kept set apart by a rule. The danger card is a card like the others; its words say what
 * it does (red only with words). */
.clear__table {
    width: 100%;
    margin: var(--space-sm) 0;
    border-collapse: collapse;
}

.clear__table th,
.clear__table td {
    padding: var(--space-3xs) 0;
    border-bottom: var(--border-width) solid var(--colour-border);
    text-align: left;
    font-weight: var(--font-weight-regular);
}

.clear__table td {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: var(--font-weight-bold);
}

.clear__row--kept th,
.clear__row--kept td {
    border-top: var(--border-width-accent) solid var(--colour-border);
}

/* The host name is typed and shown in three places; a long one wraps rather than widening a phone. */
.clear__host {
    overflow-wrap: anywhere;
}

.clear__kept {
    margin: var(--space-2xs) 0;
    padding-left: var(--space-md);
    overflow-wrap: anywhere;
}

/* ==========================================================================================
 * STANDINGS TO THE TARGET (2026-10-04 13:00 and 13:30; docs/task-briefs/standings-target.md)
 *
 * docs/design/proposals/2026-v4/standings.html, as Kenneth's test of 4/10 reshaped it: where you
 * stand as two cards (Dig, Dit hold); the tabs and the filters as pills on one row, 12px above the
 * board; the top three teams in pale medal circles; the reader's own row on a stronger tint.
 * ========================================================================================== */

/* --- Where you stand: two cards, Dig and Dit hold (the advisor's note of 4/10 23:15) ---------
 * Component sheet items 2 and 3: white cards with a hairline, 20px round, 24px inside (20 on a
 * phone), each opening with a round Ice Blue tile and a small-caps label; 1 : 1.4 side by side,
 * stacked on a phone. Their figures stand in columns divided by a hairline. */
.standcards {
    display: grid;
    /* Never wider than the screen, whatever a card's figures want (WCAG 1.4.10). */
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}

@media (min-width: 48rem) {
    .standcards {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
        gap: 24px;
    }
}

.standcard {
    display: grid;
    align-content: start;
    gap: 16px;
    padding: 20px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: 20px;
    background: var(--colour-surface);
}

@media (min-width: 48rem) {
    .standcard {
        padding: 24px;
    }
}

/* The card's heading ("Dig", "Dit hold · name"): an h2 for the reader moving by headings, drawn as the
 * sheet's card heading, 22 beside the 40px tile (item 2, 2026-10-05 16:20; no caps eyebrow). */
.standcard__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin: 0;
    color: var(--colour-text);
    font-size: 16px;
    line-height: 1.3;
    letter-spacing: normal;
}

.standcard__tile {
    display: grid;
    flex: 0 0 40px;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-text);
}

.standcard__tile .lineicon {
    width: 20px;
    height: 20px;
}

.standcard__label {
    color: var(--colour-text);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
    line-height: 1.2;
}

/* "Dit hold · Corridor Cruisers": the team's name in the title row, the heading's own size. */
.standcard__name {
    color: var(--colour-text);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
    line-height: 1.2;
}

.standcard__title {
    min-width: 0;
    flex: 1 1 0;
}

/* A no-break space before the dot and a plain one after it: a long name wraps after the dot. The
 * spoken alternative is a comma, so the heading is "Dit hold, Corridor Cruisers", never the two run
 * together (the spans touch, so the wrap cannot fall before the dot). */
.standcard__name::before {
    color: var(--colour-text-muted);
    content: "\00a0· " / ", ";
}

.standcard__figs {
    display: grid;
    grid-auto-columns: minmax(0, 1fr);
    grid-auto-flow: column;
    margin: 0;
}

.standcard__fig {
    padding-inline: 16px;
    border-left: var(--border-width) solid var(--colour-rule-warm);
}

.standcard__fig:first-child {
    padding-left: 0;
    border-left: 0;
}

.standcard__fig dt {
    color: var(--colour-text-muted);
    font-size: 13px;
    font-weight: var(--font-weight-bold);
}

.standcard__fig dd {
    margin: 0;
}

.standcard__fig strong {
    display: block;
    /* One line: "Nr. 80 af 129" broken over two reads as two figures. */
    white-space: nowrap;
    font-size: 24px;
    font-weight: var(--font-weight-heavy);
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
}

.standcard__fig small {
    display: block;
    margin-top: 2px;
    color: var(--colour-text-muted);
    font-size: 13px;
}

/* A sentence, not a figure: "Ikke placeret endnu" wraps on a narrow phone rather than push the card
 * wider than the screen (WCAG 1.4.10). Qualified, or the figures' one-line rule above wins. */
.standcard__quiet {
    color: var(--colour-text-muted);
}

.standcard__fig .standcard__quiet {
    white-space: normal;
}

/* On a phone the cards keep the system's 20 inside and 40px tile (the density rules of 4/10 23:30);
 * the figures step down to 18 so a team's three stand side by side. */
@media (max-width: 47.99rem) {
    .standcard__fig {
        padding-inline: 10px;
    }

    .standcard__fig strong {
        font-size: 18px;
    }

    /* Columns as wide as their figure (a place of "Nr. 23 af 29" needs more than a third of a
     * phone); a label wraps under it rather than the figure. */
    .standcard__figs {
        grid-auto-columns: auto;
    }
}

/* On a phone Dit hold's three figures do not fit three columns without crowding "Gns. pr. medlem"
 * (05:45): Placering and the average side by side, Medlemmer under them. */
@media (max-width: 47.99rem) {
    .standcard--team .standcard__figs {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-auto-flow: row;
        row-gap: 12px;
    }

    .standcard--team .standcard__fig:nth-child(3) {
        padding-left: 0;
        border-left: 0;
    }
}

/* Narrower than a 390 phone (a 360 phone, or 320 at 400% zoom): a place breaks between its words
 * rather than push the card past the screen (WCAG 1.4.10); its numbers keep their no-break spaces. */
@media (max-width: 24rem) {
    .standcard__fig strong {
        white-space: normal;
    }
}

.standcard__empty {
    margin: 0;
    font-size: 17px;
    font-weight: var(--font-weight-bold);
}

/* No team: the sheet's empty state (item 8) in the Dit hold card's place. */
.standcard--none {
    justify-items: center;
    gap: 8px;
    text-align: center;
}

.standcard__tile--big {
    flex-basis: 56px;
    width: 56px;
    height: 56px;
}

.standcard__none {
    margin: 0;
    color: var(--colour-text);
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    line-height: 1.4;
    letter-spacing: normal;
}

.standcard__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 16px;
    margin: 8px 0 0;
}

.standcard__actions .button {
    width: auto;
}

/* --- The one explanation, under the cards (the "i" notice, item 3) ---------------------------- */
.standings-note {
    margin: 0;
}

/* --- The board before anybody has steps (the advisor's note of 4/10 20:00; sheet item 8) ------ */
.board-empty {
    display: grid;
    justify-items: center;
    gap: 8px;
    padding: 32px 16px;
    text-align: center;
}

.board-empty__tile {
    display: grid;
    place-items: center;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-text);
}

.board-empty__tile .lineicon {
    width: 26px;
    height: 26px;
}

.board-empty__title {
    margin: 0;
    font-size: 17px;
    font-weight: var(--font-weight-bold);
}

.board-empty__line {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: 15px;
}

/* --- The controls: the tabs, and the filters as the same pill segment (FINDING 4/10 21:25) ----
 * The page stack's gap is 16px: the controls sit 24px under the cards and 12px above the board. */
.standings-controls {
    margin-top: 8px;
    margin-bottom: -4px;
}

.standings-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

.standings-filters .boardtabs {
    flex: 0 0 auto;
    /* On a computer a pill group never wraps into a second line inside its track (FINDING 21:25); on a
     * phone it does, below. */
    flex-wrap: nowrap;
}

.standings-filters .boardtabs__tab {
    white-space: nowrap;
}

/* The unplaced team's sentence takes its own line under the row. */
.standings-controls .filters__note {
    flex-basis: 100%;
    margin: 0;
}

.standings-filters__row {
    display: flex;
}

/* On a phone no choice is cut at the edge (the advisor, 2026-10-08 04:30): each filter row takes its own line
 * and its pills wrap inside their track, where they were one sideways-scrolling line (5/10 17:30) that left
 * "Mit holds EVP-område" clipped and the steps pills off the screen at 390. */
@media (max-width: 47.99rem) {
    .standings-filters {
        flex-wrap: wrap;
    }

    .standings-filters__row {
        flex: 1 1 100%;
        min-width: 0;
    }

    .standings-filters .boardtabs {
        flex: 0 1 auto;
        flex-wrap: wrap;
        min-width: 0;
    }

    /* The "i" line under the board on a phone, so the board starts nearer the fold (05:45); a
     * computer keeps it under the cards. Not read out of order: it is a note, not a step. */
    .standings-note {
        order: 1;
    }

    .standings-note ~ .pagestack__note {
        order: 2;
    }
}

/* --- The board: a place in a circle, medals for the top three, the reader's row in ink ----- */
.board-table__pos {
    display: inline-grid;
    place-items: center;
    min-width: 36px;
    height: 36px;
    padding: 0 6px;
    border-radius: var(--radius-pill);
}

.board-table__pos--medal {
    min-width: 32px;
    height: 32px;
    border: var(--border-width) solid var(--colour-border-soft);
    font-size: 14px;
}

.board-table__pos--1 {
    background: var(--colour-medal-gold);
}

.board-table__pos--2 {
    background: var(--colour-medal-silver);
}

.board-table__pos--3 {
    background: var(--colour-medal-bronze);
}

/* THE READER'S ROW: the stronger tint on its cells (Blink paints no row background under rounded
 * cells), its place in an ink circle and the tag filled ink. No side stripe: v4 draws none.
 * SCOPED TO THE STANDINGS PANEL: the admin support list is a .board-table too, and marks its
 * selected row with the same class in its own colours (admin.css). */
.board-panel .board-table__row--you {
    background: none;
}

.board-panel .board-table tbody .board-table__row--you > th,
.board-panel .board-table tbody .board-table__row--you > td {
    background: var(--colour-surface-own-row);
    font-weight: var(--font-weight-heavy);
}

.board-panel .board-table__row--you > *:first-child {
    box-shadow: none;
    border-radius: 12px 0 0 12px;
}

.board-panel .board-table__row--you > *:last-child {
    border-radius: 0 12px 12px 0;
}

/* The reader's team among the top three keeps its medal's size, filled ink like any own row. */
.board-panel .board-table__row--you .board-table__pos {
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
}

.board-panel .board-table__row--you .board-table__you {
    border: 0;
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
}

/* --- Grand Team's numbered winners (ten winners, Line 28/9) -----------------------------------------
 * The place number is written out in the item (the base list rule turns the markers off, so a screen
 * reader and the eye get the same number). The number, the team and its flags wrap as they need;
 * "Replace" keeps the row's far end (design review, 4/10: it moved with the length of the flag text). */
.competitions-admin__teams--numbered > li {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: var(--space-2xs);
}

.competitions-admin__slot {
    display: inline-block;
    min-width: 2ch;
    font-variant-numeric: tabular-nums;
}

.competitions-admin__replace {
    margin-left: auto;
    font-size: var(--font-size-sm);
}

/* --- When the winners are announced (advisor 4/10 12:00) ------------------------------------------
 * One quiet line under a card's tiles when an administrator set the date: muted, small, no tile. */
.competition__announce {
    margin: var(--space-xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* ==========================================================================================
 * THE NOTICES IN v4 (the advisor, 2026-10-04 21:30; docs/task-briefs/status-notices-v4.md)
 *
 * A participant's notice stands on the band tint inside a hairline, 16px round, with no side
 * stripe: v4 draws none. What kind of notice it is no longer rests on a stripe's width or hue: a
 * small round tile leads it, with a mark in it, and the words already say it (WCAG 2.2 AA 1.4.1).
 *   - a plain notice or a fact (.status, .status--info): an "i", white on Lasting Blue. Plain .status
 *     is not only a confirmation: a refusal or a stale page lands there too ("the roster has just
 *     closed"), so it takes the neutral mark, never a check (code review);
 *     a confirmation that is one says so with .status--success and its own check;
 *   - a reason to act or a refusal (.status--warning, .status--error): a "!", white on Lava Red,
 *     with the hairline in Lava Red too — red only together with the mark and the words.
 * The tile is decoration for the ear (its alternative text is empty): the sentence carries it.
 * A saved band (.status--success) draws its own check in its markup and keeps it.
 * The admin shell's flashes and notes take the same "i" tile in admin.css (audit 1006, D7); none of
 * these rules reaches it.
 * ========================================================================================== */
body:not(.adminshell) .status:not(.status--success) {
    position: relative;
    min-height: 52px;
    padding: 14px 18px 14px 52px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: 16px;
    background: var(--colour-surface-band);
    color: var(--colour-text);
}

body:not(.adminshell) .status:not(.status--success)::before {
    position: absolute;
    top: 14px;
    left: 16px;
    display: grid;
    place-items: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
    font-size: 14px;
    font-weight: var(--font-weight-heavy);
    line-height: 1;
    content: "i" / "";
}

body:not(.adminshell) .status.status--warning:not(.status--success),
body:not(.adminshell) .status.status--error:not(.status--success) {
    border-color: var(--colour-danger);
}

body:not(.adminshell) .status.status--warning:not(.status--success)::before,
body:not(.adminshell) .status.status--error:not(.status--success)::before {
    background: var(--colour-danger);
    content: "!" / "";
}

/* Windows High Contrast drops the tile's ground: a system-coloured ring keeps it a tile. */
@media (forced-colors: active) {
    body:not(.adminshell) .status:not(.status--success)::before {
        border: 1px solid CanvasText;
    }
}

/* --- My team, polished to the v4 target (team.html; advisor 2026-10-04 14:00, "polish, not
 * redesign"). LAST, because each rule restates a selector an earlier layer already styled at the
 * same specificity, and source order is what decides between them (novo-css-cascade-traps). */

/* Remove (and Delete beside an invitation, the same class) is the quiet word in the row: 13px
 * regular in the muted ink, underlined only when a pointer or the keyboard is on it. It keeps
 * its 44px target from the base rule. */
.roster-panel .roster-table__action--text {
    color: var(--colour-text-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-regular);
    text-decoration: none;
}

.roster-panel .roster-table__action--text:hover,
.roster-panel .roster-table__action--text:focus-visible {
    color: var(--colour-text);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* A join request: Approve stays the solid button; Decline is the quiet underlined word beside it,
 * still a 44px button with the full name in its accessible name. */
.requests .requests__decline {
    border-color: transparent;
    background: transparent;
    color: var(--colour-text-muted);
    font-size: var(--font-size-base);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.requests .requests__decline:hover {
    background: transparent;
    color: var(--colour-text);
}

/* The deadline card has more air. */
.teamwork .deadline-panel {
    gap: 14px;
    padding: 22px;
}

/* --- My steps, polished to the v4 target (steps.html; advisor 2026-10-04 14:00, "polish, not
 * redesign"). LAST, for the same reason as My team's section above: each rule restates a selector
 * an earlier layer styles at the same specificity, and source order decides. */

/* More air inside each day. A state still never changes a tile's size: today's ring and the
 * dashed edit stay inset outlines. */
.dtile {
    gap: 8px;
    padding: 15px 14px;
}

/* Today is clearer: a stronger tint under the ink ring, and a soft lift. */
.dtile--is-today {
    background: var(--steps-today-ground);
    box-shadow: var(--steps-today-lift);
}

/* Save is the page's one action, so it is the sheet's large button (.button--lg, 56; advisor
 * 2026-10-05 11:30): its 18px label and 40px sides, heavy. It was 62 tall at 19px. */
.days__actions {
    gap: 12px;
}

.days__actions .days__save {
    padding: 0 40px;
    font-size: 18px;
    font-weight: var(--font-weight-heavy);
}

/* The calculator's answer has weight: a white box with an ink edge and a 32px figure, 240px wide
 * as the target draws it. The body that reserves the answer's width (180px before) widens to
 * match, and may shrink on a narrow phone rather than push the card sideways (WCAG 1.4.10). */
.steps-page .converter__result-body {
    flex: 0 1 240px;
    width: 240px;
    max-width: 100%;
    min-width: 0;
}

.steps-page .converter__result-value {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 100%;
    min-height: 62px;
    padding: 0 18px;
    border: 2px solid var(--colour-primary);
    border-radius: 12px;
    background: var(--colour-surface);
    font-size: 32px;
    font-weight: var(--font-weight-heavy);
    line-height: 1.1;
}

/* No answer yet stays a light dash (F-055: "a bold dash at 42 is a bar"); only a figure is heavy. */
.steps-page .converter__result--empty .converter__result-value {
    font-weight: var(--font-weight-regular);
}

@media (min-width: 48rem) {
    .steps-page .converter {
        gap: 16px;
        padding: 28px 28px 30px;
    }
}

/* --- The front page's materials button (advisor 2026-10-04 16:45): under the tiles ---------- */
.front__materials-open {
    margin: 0;
}

.front__materials-open .button {
    width: auto;
    gap: var(--space-2xs);
}

@media (min-width: 62.5rem) {
    .front__materials-open {
        grid-column: 2;
        margin-top: -8px;
    }
}

/* --- A join request waiting (advisor 2026-10-04 18:10): a status, not a paragraph. One tint card
 * with a round Ice Blue check tile, a bold line and one plain line; the quiet withdrawal under it. */
.reqcard {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    margin-top: var(--space-lg);
    padding: 20px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: 18px;
    background: var(--colour-surface-band);
}

.gatecard > .reqcard:first-child {
    margin-top: 0;
}

.reqcard__tile {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-primary);
}

.reqcard__tile .lineicon {
    width: 22px;
    height: 22px;
}

.reqcard__words {
    min-width: 0;
}

.reqcard .reqcard__title {
    margin: 0;
    font-size: var(--font-size-lg);
    line-height: var(--line-height-tight);
}

.reqcard__line {
    margin: 6px 0 0;
    color: var(--colour-text-muted);
    font-size: 15px;
}

.reqcard__withdraw {
    margin-top: 12px;
}

.reqcard__withdraw .link-button {
    font-size: 15px;
}

/* A short gate card starts at the top of the content, as the other guest cards do, instead of being
 * centred beside the tall prints column (Find your team; advisor 2026-10-04 19:00). */
.gatemain:has(> .gatemain__inner > .gatecard--top) {
    align-items: flex-start;
}

.gatemain__inner > .gatecard--top {
    align-self: start;
}

/* --- My team: the team just formed (advisor 2026-10-04 17:30). b1's v4 status notice - the band
 * tint, a hairline, the "i" tile - with one line under its title. */
.teamborn .teamborn__line {
    margin: 4px 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

/* --- My team, the advisor's design OK fixes (2026-10-04 19:00) --------------------------------- */

/* "Your team is created" is the positive moment: the same tint card, a check in its tile. */
body:not(.adminshell) .status.teamborn::before {
    content: "✓" / "";
}

/* The deadline's date is one line at 22px/800, not a heading's size over two. */
.teamwork .deadline-panel .deadline-panel__date {
    font-size: 22px;
    font-weight: var(--font-weight-heavy);
    line-height: 1.2;
}

/* The time and its zone under it in the second voice: the zone must stay (23:59 is one moment only
 * with it), but it is not a second heading. */
.teamwork .deadline-panel .deadline-panel__time {
    margin-top: 2px;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
}

/* "Created a team by mistake? Delete it ..." is a quiet line: its link regular weight. */
.alone-line .text-link--inline {
    font-weight: var(--font-weight-regular);
}

/* --- The converter's controls in v4 (Kenneth's test, 2026-10-04: the native lists "not very
 * pretty") ----------------------------------------------------------------------------------
 *
 * THE QUESTION AN ACTIVITY ASKS, as one segmented choice: the activity's own answers as pills on
 * the tint, the chosen one filled, as the language choice on Mine oplysninger draws them (the
 * component sheet's item 5). Real radios in a fieldset; each radio stays in the page, out of
 * sight but focusable, and its focus is drawn on its pill. Pills wrap rather than overflow: a
 * method or a load names its answers in more words than an intensity. */
.converter__choices-group {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

/* A legend otherwise sits across the fieldset's top edge; floated, it is an ordinary first line
 * like the other fields' labels. */
.converter__choices-group > legend {
    float: left;
    width: 100%;
    padding: 0;
}

.converter__choices {
    display: flex;
    flex-wrap: wrap;
    clear: both;
    gap: 4px;
    padding: 4px;
    /* White on the converter's tinted card, edged as the fields beside it are; 56 tall with its
     * 48px pills, the row's own field height. */
    background: var(--colour-surface);
    border: 1px solid var(--colour-border-field);
    border-radius: 14px;
}

/* SIZED TO ITS ANSWERS WHEN IT ASKS. The column was a measured 180 for a select; three pills do not
 * fit there, so while it holds pills it takes their width, on one line, and the activity gives way.
 * On a phone the pills take their own full line under the activity. */
.converter__row .converter__field--qualifier:has(.converter__choices) {
    flex: 0 0 auto;
}

@media (min-width: 48rem) {
    .converter__row:has(.converter__choices) {
        grid-template-columns: 1fr 120px max-content;
    }

    .converter__choices {
        flex-wrap: nowrap;
    }

    .converter__choice-label {
        white-space: nowrap;
    }
}

@media (max-width: 47.99rem) {
    .converter__row .converter__field--qualifier:has(.converter__choices) {
        flex: 1 1 100%;
    }
}

.converter__choice {
    position: relative;
    display: inline-flex;
    flex: 1 1 auto;
}

.converter__choice-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.converter__choice-label {
    display: inline-flex;
    flex: 1 1 auto;
    align-items: center;
    justify-content: center;
    min-height: 46px;
    padding: 0 14px;
    border-radius: 10px;
    color: var(--colour-text-muted);
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    text-align: center;
}

.converter__choice-input:checked + .converter__choice-label {
    background: var(--colour-primary);
    color: var(--colour-text-on-primary);
}

.converter__choice-input:not(:checked):hover + .converter__choice-label {
    color: var(--colour-text);
}

.converter__choice-input:focus-visible + .converter__choice-label {
    outline: var(--focus-ring-width) solid var(--colour-focus);
    outline-offset: var(--focus-ring-offset);
}

.converter__choice-input[aria-invalid="true"] + .converter__choice-label {
    color: var(--colour-text);
}

/* THE SEARCHABLE LIST (item 11), built by public/js/picker.js over a select[data-picker] (which it
 * hides and still submits): the converter's activity and the team's country. The input is the field
 * the row already draws; the list opens under it as
 * the v4 card: white, 12px corners, a hairline, 44px rows, the band tint under the pointer and
 * the keyboard's place, the chosen activity in heavy ink with a check. */
.picker {
    position: relative;
}

/* Outside the converter (the team's country) the input is the item-12 box with the selects' own
 * chevron 16 from the right and 40 inside, as the EVP select beside it. */
.picker__input {
    padding-right: 40px;
    background: var(--colour-surface) url('../img/chevron-down.svg') no-repeat right 16px center;
}

.converter .picker__input {
    width: 100%;
    height: 56px;
    padding: 0 44px 0 16px;
    border: 1px solid var(--colour-border-field);
    border-radius: 14px;
    /* The chevron is the product's own file: the CSP refuses a data: image (img-src 'self'). */
    background: var(--colour-surface) url('../img/chevron-down.svg') no-repeat right 16px center;
    font-size: 16px;
    color: var(--colour-text);
}

.picker__list {
    position: absolute;
    z-index: 20;
    top: calc(100% + 4px);
    left: 0;
    width: max(100%, 18rem);
    max-height: 22rem;
    overflow-y: auto;
    padding: 6px 0;
    background: var(--colour-surface);
    border: 1px solid var(--colour-rule-warm);
    border-radius: 12px;
    box-shadow: var(--steps-today-lift);
}

.picker__heading {
    padding: 10px 16px 4px;
    color: var(--colour-text-muted);
    font-size: 12px;
    font-weight: var(--font-weight-heavy);
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.picker__option {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
    padding: 0 16px;
    color: var(--colour-text);
    font-size: 16px;
    cursor: pointer;
}

.picker__option:hover,
.picker__option--active {
    background: var(--colour-surface-band);
}

/* THE KEYBOARD'S ROW SAYS SO, AND NOT BY THE TINT ALONE (advisor 2026-10-05 17:30): the tint is
 * #F2F2FA on white, about 1.1:1, so the row Enter will choose also carries a 2px Lasting Blue inset
 * edge on its left, which hover does not share. Both pickers. */
.picker__option--active {
    box-shadow: inset 2px 0 0 var(--colour-text);
}

.picker__option[aria-selected="true"] {
    font-weight: var(--font-weight-heavy);
}

.picker__option[aria-selected="true"]::after {
    content: "✓" / "";
    margin-left: auto;
    font-weight: var(--font-weight-heavy);
}

.picker__empty {
    padding: 12px 16px;
    color: var(--colour-text-muted);
}

/* In forced colours the tint and the fill are dropped: the keyboard's place and the chosen answer
 * keep an edge of their own. */
@media (forced-colors: active) {
    .picker__option--active {
        outline: 2px solid Highlight;
        outline-offset: -2px;
    }

    .converter__choice-input:checked + .converter__choice-label {
        outline: 2px solid Highlight;
    }
}

/* THE CONVERTER READS AS A CALCULATION (the component sheet, 23:00): activity → duration → the
 * question → = the answer. Each control's label carries its step number, a small ink circle the
 * label's words follow (aria-hidden: a screen reader hears the words); on a laptop a thin arrow
 * stands in the gap after the first two. On a phone the controls stack in that order, the answer
 * last, and no arrow is drawn. */
.converter__step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--colour-primary);
    color: var(--colour-text-on-primary);
    font-size: 11px;
    font-weight: var(--font-weight-heavy);
    line-height: 1;
    vertical-align: 1px;
}

@media (min-width: 80rem) {
    .converter__row {
        column-gap: 28px;
    }

    .converter__row > .converter__field {
        position: relative;
    }

    /* Centred in the gap, level with the middle of a 56px control. The alt text after the slash is
     * empty, so assistive technology reads nothing for it. */
    .converter__row > .converter__field:not(.converter__field--qualifier)::after {
        content: "→" / "";
        position: absolute;
        right: -21px;
        bottom: 19px;
        color: var(--colour-text-muted);
        font-size: 16px;
        line-height: 1;
        pointer-events: none;
    }
}

/* --- The invitation's outcome, in its panel (Kenneth's test, 4/10): the sent card or the refusal
 * sits between the panel's heading and the field, with the panel's own spacing. */
.invite .invite__sent,
.invite .invite__refused {
    margin: 0 0 16px;
}

.invite .invite__sent .reqcard__title {
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    overflow-wrap: anywhere;
}

/* Focus lands in the field after a send; the card and the label above it come into view with it,
 * and the margin grows with the text (rem, design review). */
.invite #email {
    scroll-margin-top: 11.5rem;
}

/* === THE INVITATION PANEL, UNDER THE BAND ON A PHONE AND BESIDE THE ROSTER FROM 64REM ============
 * team/show.blade.php draws the panel once, before the roster, so a phone reads it straight under
 * the band (advisor, 4/10). From 64rem .teamwork--beside lets the two columns' boxes step aside
 * (display: contents) and places every panel on one grid: the roster down the left across all the
 * rows, the side column's panels one row each on the right, in the order the board draws them.
 * The last row is 1fr, so a roster taller than the side column grows that row and not the gaps
 * between the side panels; an empty row (no requests, no deadline) is zero high, which is why the
 * spacing is the panels' own margin rather than a row gap.
 *
 * Who has asked to join is the phone copy here too, at the top of the right column: it comes
 * before the invitation in the source, so the reading order down the right column stays its
 * visual order. The desk copy is for the just-formed team, whose invitation stays on the left.
 *
 * THE PRICE, ACCEPTED FOR THE PHONE ORDER: from 64rem the source order (requests, invitation,
 * roster, deadline, place) is not the two columns' order, so Tab goes from the top of the right
 * column into the roster and back to the right column below it (design review, 4/10: not a 2.4.3
 * failure - the panels are independent, and the action before its result is a meaningful order -
 * but no CSS-only layout keeps both the phone order and the columns with one #email). */
@media (min-width: 64rem) {
    .teamwork.teamwork--beside {
        grid-template-rows: repeat(5, auto) 1fr;
        row-gap: 0;
    }

    .teamwork--beside > .teamwork__main,
    .teamwork--beside > .teamwork__aside {
        display: contents;
    }

    .teamwork--beside > .teamwork__main > *,
    .teamwork--beside > .teamwork__aside > * {
        grid-column: 2;
        align-self: start;
        margin: 0 0 20px;
    }

    .teamwork--beside > .teamwork__aside > :last-child {
        margin-bottom: 0;
    }

    .teamwork--beside > .teamwork__main > .roster-panel {
        grid-column: 1;
        grid-row: 1 / -1;
        margin: 0;
    }

    .teamwork--beside .requests-panel--phone {
        display: block;
        grid-row: 1;
    }

    .teamwork--beside .requests-panel--desk {
        display: none;
    }

    .teamwork--beside .invite-panel {
        grid-row: 2;
    }

    .teamwork--beside .deadline-panel {
        grid-row: 3;
    }

    .teamwork--beside .place-panel {
        grid-row: 4;
    }

    .teamwork--beside .alone-line {
        grid-row: 5;
    }
}

/* "INVITATION SENDT" WAITS IN INK, not amber (advisor, 4/10): v4 keeps colour for status to red and
 * green, and an invitation nobody has answered yet is neither. The neutral ground and an ink dot,
 * as the standings' state chip draws "waiting"; the word carries the state. Both live asks stay
 * one rule, so they cannot drift apart. */
.statepill--invited,
.statepill--reminder_sent {
    background: var(--colour-surface-band);
    color: var(--colour-text);
}

/* --- The stat row (the component sheet, item 2: My steps, My team, admin Overview) -------------
 *
 * Four cards, 2×2 on a phone: a round Ice Blue tile, then the label, the figure and an optional
 * small line. Measured as the sheet draws it: 76px tall at least, 14/16 padding, 16px corners, a
 * 40px tile, a 13px bold muted label, a 20px heavy figure, a 13px muted note. A card that is a
 * link takes the ink edge under the pointer and the focus ring. `--warn` is the missing day's
 * ground and edge; `--ok` the green tile. Shared: resources/views/partials/stat-row.blade.php.
 *
 * NAMED figrow/figcard, NOT statrow/statcard: those names belong to an older figures panel whose
 * rules are still scattered through this sheet with no view left using them, and they would bleed
 * into this component. */
.figrow {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    margin: 0;
    padding: 0;
    list-style: none;
}

@media (min-width: 48rem) {
    .figrow {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

.figrow__item {
    display: flex;
    min-width: 0;
}

.figcard {
    display: flex;
    flex: 1 1 auto;
    gap: 12px;
    align-items: center;
    min-width: 0;
    min-height: 76px;
    padding: 14px 16px;
    background: var(--colour-surface);
    border: 1px solid var(--colour-rule-warm);
    border-radius: 16px;
    color: var(--colour-text);
    text-align: left;
    text-decoration: none;
}

a.figcard:hover {
    border-color: var(--colour-primary);
}

a.figcard:focus-visible {
    outline: var(--focus-ring-width) solid var(--colour-focus);
    outline-offset: var(--focus-ring-offset);
}

.figcard__tile {
    display: flex;
    flex: 0 0 40px;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-primary);
}

.figcard__tile .lineicon {
    width: 20px;
    height: 20px;
}

.figcard__words {
    display: grid;
    min-width: 0;
}

.figcard__label {
    color: var(--colour-text-muted);
    font-size: 13px;
    font-weight: var(--font-weight-bold);
}

.figcard__value {
    font-size: 20px;
    font-weight: var(--font-weight-heavy);
    line-height: 1.15;
    overflow-wrap: anywhere;
}

.figcard__note {
    color: var(--colour-text-muted);
    font-size: 13px;
}

.figcard--warn {
    background: var(--steps-missing-ground);
    border-color: var(--steps-missing-edge);
}

.figcard--warn .figcard__tile {
    background: var(--colour-surface);
    border: 2px solid var(--colour-danger);
    color: var(--colour-danger);
}

.figcard--ok .figcard__tile {
    background: var(--board-tile-green);
    color: var(--colour-success);
}

@media (forced-colors: active) {
    .figcard__tile {
        border: 1px solid CanvasText;
    }
}

/* --- The stat row: three, and a phone (b3, My steps; design review 4/10) ----------------------
 * THREE WHEN THE FOURTH HAS NOTHING TRUE TO SAY (My steps on day 1, before the start, frozen): the
 * three share the row on a computer, and on a phone the third takes the second row whole, so the
 * row never shows a card-shaped hole. */
@media (min-width: 48rem) {
    .figrow:has(> :nth-child(3):last-child) {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

@media (max-width: 47.9375rem) {
    .figrow > :nth-child(3):last-child {
        grid-column: 1 / -1;
    }

    /* The card across the whole row has the room the two-by-two cards lack, so it keeps the sheet's
     * 14/16 inside (the last polish, 2026-10-05 21:00: the finished My steps' team card). */
    .figrow > :nth-child(3):last-child > .figcard {
        padding: 14px 16px;
    }

    /* Two by two in a 354px column: a smaller tile (32px) and figure (15px, the sheet's heavy
     * weight) keep each figure on one line - "54 653 skridt" is the long one - so a page head stays
     * short (My steps' day card and Save come up). The row keeps the sheet's 12px gap; the card's
     * padding is 12px, its inner gap 10px and its height 64px at least. */
    .figcard {
        gap: 10px;
        min-height: 64px;
        padding: 12px;
    }

    .figcard__tile {
        flex-basis: 32px;
        width: 32px;
        height: 32px;
    }

    .figcard__tile .lineicon {
        width: 16px;
        height: 16px;
    }

    .figcard__label,
    .figcard__note {
        font-size: 12px;
    }

    .figcard__value {
        font-size: 15px;
    }
}

/* --- My steps: the campaign's own days (Kenneth 4/10) ------------------------------------------ */

/* A campaign of a week or less is one row of its own days: four days, four wide cards. */
.week__row--fit {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
}

/* The range beside a short campaign's heading, in the weeks' own quiet weight. */
.days__range {
    color: var(--colour-text-muted);
    font-weight: var(--font-weight-regular);
}

/* The days' card takes the sheet's 24px padding (the density pass; advisor 2026-10-05 03:30). */
@media (min-width: 48rem) {
    .card.days__card--desk {
        padding: 24px;
    }
}

/* === A CONFIRMATION IS DRAWN AS THE DIALOG'S CARD (component sheet item 9; advisor 2026-10-05) ===
 * The team's confirmations (remove, delete, rotate the link, revoke, hand over, make captain,
 * switch, create instead) stay pages, so they work without JavaScript (ADR 020). Each is the white
 * page with the dialog's card centred under the bar: 24px corners, 28px inside, 420px at most, the
 * first-save dialog's lift. NO SCRIM: on a full page a 40 % ink panel read as a lavender block, not
 * as a dimmed page (advisor 05:45); the scrim is only for a real modal <dialog> (dialog::backdrop,
 * and the contract says so). create-instead carries a whole form, so its card is 560px. */
main:has(> .decision) {
    display: grid;
    justify-items: center;
    align-content: start;
    padding-top: 24px;
}

main > .decision {
    width: min(420px, 100%);
    margin: 0;
    padding: 28px;
    border-radius: 24px;
    box-shadow: var(--steps-today-lift);
}

main > .decision--form {
    width: min(560px, 100%);
    /* The bare .decision's 34rem cap (544px) would hold it short of the sheet-width form card. */
    max-width: none;
}

/* IN THE DIALOG THE ANSWER AND THE WAY OUT STACK AT EVERY WIDTH, both the card's full width: the
 * card is narrower than the width at which this component already stacks them on a phone, and side
 * by side they wrapped by the length of a member's name, the way out wider than the answer (design
 * review). */
main > .decision .decision__actions {
    flex-direction: column;
    align-items: stretch;
}

main > .decision .decision__actions form,
main > .decision .decision__actions .button,
main > .decision .decision__actions > a {
    width: 100%;
}

/* The way out is as tall and as large as the answer above it (consistency round 2026-10-05, item 12):
 * it was the quiet button's 44 at 15px under a 48 primary. */
main > .decision .button--quiet.decision__decline {
    min-height: var(--button-height-secondary);
    font-size: var(--font-size-base);
}

@media (max-width: 47.9375rem) {
    main:has(> .decision) {
        padding-top: var(--space-sm);
    }

    main > .decision {
        padding: var(--space-md);
    }
}

/* === MY TEAM TO THE COMPONENT SHEET (advisor 2026-10-05 03:50: items 2, 3, 7, 10) =============
 * Item 2 adds nothing here: the figure band stays (the rollout note of 2026-10-04 23:00, "the band
 * stays"). The rest is measured against the sheet and set LAST, because each rule restates a
 * selector an earlier layer styles at the same specificity. */

/* Item 10, the card: 20px corners, 24px inside, the sheet's soft lift. */
.teamwork .panel {
    border-radius: 20px;
    box-shadow: 0 10px 30px color-mix(in srgb, var(--colour-primary) 5%, transparent);
}

.teamwork .panel .panel__title {
    font-size: 22px;
    line-height: 1.2;
}

/* The deadline is the sheet's quiet card: the band tint, no edge, no lift. */
.teamwork .deadline-panel {
    padding: 24px;
    border-color: transparent;
    border-radius: 20px;
    background: var(--colour-surface-band);
    box-shadow: none;
}

/* Item 7, the table: quiet rule lines between rows, a 12px heavy tracked head with no band behind
 * it, 10px cells, and the reader's own row on the stronger tint in bold. Where the roster and the
 * invitations are tables (from 1280 and 1408); below that each row is its own stacked card. */
@media (min-width: 80rem) {
    .roster-panel .roster-table:not(.roster-table--invites) th,
    .roster-panel .roster-table:not(.roster-table--invites) thead th {
        padding: 10px;
        border-bottom: 0;
        background: none;
        color: var(--colour-text-muted);
        font-size: 12px;
        font-weight: var(--font-weight-heavy);
        letter-spacing: 0.1em;
    }

    .roster-panel .roster-table:not(.roster-table--invites) td {
        padding: 10px;
        border-top: 1px solid var(--colour-rule-warm);
        border-bottom: 0;
    }

    .roster-panel .roster-table__row--you td {
        background: var(--colour-surface-own-row);
        border-top-color: transparent;
        font-weight: var(--font-weight-heavy);
    }

    .roster-panel .roster-table__row--you + tr td {
        border-top-color: transparent;
    }

    .roster-panel .roster-table__row--you td:first-child {
        border-radius: 10px 0 0 10px;
    }

    .roster-panel .roster-table__row--you td:last-child {
        border-radius: 0 10px 10px 0;
    }
}

@media (min-width: 88rem) {
    .roster-panel .roster-table--invites th {
        padding: 10px;
        border-bottom: 0;
        font-size: 12px;
        font-weight: var(--font-weight-heavy);
        letter-spacing: 0.1em;
    }

    .roster-panel .roster-table--invites td {
        padding: 10px;
        border-top: 1px solid var(--colour-rule-warm);
        border-bottom: 0;
    }
}

/* Item 3, the status card, for the invitation's outcome and a join request waiting: the band tint,
 * 16px corners, 14/16 inside, a 28px round mark, the bold line and a 15px muted one. */
.reqcard {
    gap: 12px;
    padding: 14px 16px;
    /* No edge: the sheet's done and fact cards draw none (only its warning has one). Transparent
     * rather than removed, so forced-colours mode still draws the card. */
    border-color: transparent;
    border-radius: 16px;
}

.reqcard__line {
    margin-top: 2px;
}

.reqcard__tile {
    width: 28px;
    height: 28px;
}

.reqcard__tile .lineicon {
    width: 16px;
    height: 16px;
}

.reqcard .reqcard__title {
    font-size: 16px;
}

/* WHERE THE CARD IS THE WHOLE PAGE (a join request waiting, on /team/find), its title is the page's
 * h1: it keeps the size a page heading needs, so the page does not read as headingless (design
 * review). The card around it is still the sheet's. */
.reqcard h1.reqcard__title {
    font-size: var(--font-size-lg);
}

/* Item 7's tag: the captain chip is the sheet's `.tag`, white words on an ink pill, 12px heavy, on
 * any row (the reader's tinted own row included). The words carry the role. */
.roster-panel .roster-table__badge {
    padding: 3px 9px;
    border-color: transparent;
    border-radius: var(--radius-pill);
    background: var(--colour-primary);
    color: var(--colour-text-inverse);
    font-weight: var(--font-weight-heavy);
}

/* === THE STATUS CARDS TO THE COMPONENT SHEET (item 3; advisor 2026-10-05 03:50) ================
 * "check = done, i = fact, ! = missing/refused": the band tint, 16px corners, 14/16 inside, a 28px
 * round mark and the words beside it. A fact and a done card draw no edge (the sheet draws none); a
 * reason to act stands on the calm red ground with its soft edge, as the missing-day card does, its
 * mark Lava Red with the "!" in white. The words carry the meaning; the mark and the ground repeat
 * it (WCAG 2.2 AA 1.4.1). My steps' saved band keeps its own ink (more specific rules), and the
 * admin shell keeps its own notices. Set LAST, over "THE NOTICES IN v4". */
body:not(.adminshell) .status:not(.status--success) {
    min-height: 56px;
    padding: 14px 16px 14px 56px;
    border-color: transparent;
}

body:not(.adminshell) .status:not(.status--success)::before {
    top: 14px;
    left: 16px;
    width: 28px;
    height: 28px;
    font-size: 14px;
}

body:not(.adminshell) .status.status--warning:not(.status--success),
body:not(.adminshell) .status.status--error:not(.status--success) {
    border-color: var(--steps-missing-edge);
    background: var(--steps-missing-ground);
}

/* "Team created" is a done, so its mark is the done tile: the check in Lasting Blue on Ice Blue. */
body:not(.adminshell) .status.teamborn::before {
    background: var(--colour-surface-tile);
    color: var(--colour-primary);
}

/* === MY TEAM'S PHONE ROSTER IN TWO LINES (advisor 2026-10-05 06:30) ===========================
 * Below 1280 a member was five stacked lines (about 180px): the mark and name, the total, the
 * entered days, and Remove each on its own line. Two lines now, about 60px a row:
 *   line 1: the rank · the mark, the name and the captain chip · the total, right-aligned;
 *   line 2: "6 af 10 indtastet" in the muted voice · Remove, quiet, on the right.
 * Remove keeps a 44px-tall target: the padding that makes it is taken back by a negative margin,
 * so the target is full height while the line stays a line of text. */
@media (max-width: 79.999rem) {
    .roster-panel .roster-table:not(.roster-table--invites) .roster-table__row {
        grid-template-columns: 1.5rem minmax(0, 1fr) auto;
        align-items: center;
        gap: 2px var(--space-2xs);
        padding: 8px 0;
    }

    .roster-panel .roster-table:not(.roster-table--invites) td {
        padding: 0;
    }

    /* The initials mark steps down to 26px, so it sets no taller a first line than the name. */
    .roster-panel .roster-table:not(.roster-table--invites) .roster-table__mark {
        flex: 0 0 26px;
        width: 26px;
        height: 26px;
        font-size: 11px;
    }

    /* The name is never cut: it wraps beside its mark. */
    .roster-panel .roster-table:not(.roster-table--invites) td.roster-table__name {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 2px 8px;
        min-width: 0;
        grid-column: 2;
        grid-row: 1;
    }

    /* A long name wraps rather than being cut: a name is the one thing a row must say whole. */
    .roster-panel .roster-table:not(.roster-table--invites) td.roster-table__name .roster-table__person {
        flex: 1 1 0;
        min-width: 0;
        white-space: normal;
        overflow-wrap: anywhere;
    }

    /* The captain's chip has its own line under the name (a full-width break before it), so neither
     * the name nor the chip is squeezed; only the captain's row is three lines. */
    .roster-panel .roster-table:not(.roster-table--invites) td.roster-table__name::after {
        content: "";
        flex-basis: 100%;
        height: 0;
        order: 1;
    }

    .roster-panel .roster-table:not(.roster-table--invites) .roster-table__badge {
        flex-shrink: 0;
        order: 2;
        margin: 0 0 0 34px;
    }

    .roster-panel .roster-table:not(.roster-table--invites) td.roster-table__figure {
        grid-column: 3;
        grid-row: 1;
        text-align: right;
    }

    .roster-panel .roster-table:not(.roster-table--invites) td.roster-table__figure--quiet {
        grid-column: 2;
        grid-row: 2;
        text-align: left;
        font-size: 13px;
        line-height: 22px;
    }

    .roster-panel .roster-table:not(.roster-table--invites) .roster-table__figure--quiet::before {
        content: none;
    }

    .roster-panel .roster-table:not(.roster-table--invites) .roster-table__figure--quiet::after {
        content: " " attr(data-label);
        text-transform: lowercase;
    }

    .roster-panel .roster-table:not(.roster-table--invites) td.roster-table__action-cell {
        grid-column: 3;
        grid-row: 2;
        justify-self: end;
    }

    .roster-panel .roster-table:not(.roster-table--invites) td.roster-table__action-cell a,
    .roster-panel .roster-table:not(.roster-table--invites) td.roster-table__action-cell button {
        min-height: 0;
        margin: -10px 0;
        padding: 10px 0;
        font-size: 13px;
        line-height: 22px;
    }

    .roster-panel .roster-table:not(.roster-table--invites) td.roster-table__action-cell {
        line-height: 22px;
    }
}

/* THE INVITATIONS IN TWO LINES TOO (advisor 2026-10-05 06:30), wherever they are stacked (below 1408):
 *   line 1: the address (it breaks only at its @) · the date, muted, on the right;
 *   line 2: the state chip · Send a reminder and Delete, quiet, on the right.
 * The reminder was a bordered button on its own line; in the stacked list it is a quiet text action
 * like Delete, its 44px target kept by padding that a negative margin takes back. */
@media (max-width: 87.999rem) {
    .roster-panel .roster-table--invites .roster-table__row {
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: center;
        gap: 4px 10px;
        padding: 8px 0;
    }

    .roster-panel .roster-table--invites td.roster-table__address {
        grid-column: 1;
        grid-row: 1;
        overflow-wrap: normal;
    }

    .roster-panel .roster-table--invites .roster-table__row > td:nth-child(2) {
        grid-column: 1;
        grid-row: 2;
    }

    .roster-panel .roster-table--invites td.roster-table__when {
        grid-column: 2;
        grid-row: 1;
        text-align: right;
        font-size: 13px;
        line-height: 22px;
    }

    .roster-panel .roster-table--invites td.roster-table__action-cell {
        grid-column: 2;
        grid-row: 2;
        justify-self: end;
    }

    .roster-panel .roster-table--invites .roster-table__actions {
        flex-wrap: nowrap;
        gap: 16px;
    }

    .roster-panel .roster-table--invites .roster-table__action,
    .roster-panel .roster-table--invites .roster-table__action--text {
        min-height: 0;
        margin: -10px 0;
        padding: 10px 0;
        border: 0;
        background: none;
        color: var(--colour-text);
        font-size: 13px;
        font-weight: var(--font-weight-bold);
        line-height: 22px;
        text-decoration: underline;
        text-underline-offset: 3px;
    }

    .roster-panel .roster-table--invites .roster-table__action--text {
        font-weight: var(--font-weight-regular);
        color: var(--colour-text-muted);
    }
}

/* === THE FINISHED STATES TO THE COMPONENT SHEET (advisor 2026-10-05 08:40) ===================== */

/* The diplomas page: each diploma's card leads with the sheet's tile heading (item 10, laid out by
 * the shared card-heading rule) and is the sheet's card - 20px corners, the soft lift. */
.diplomas__title {
    font-size: 22px;
    line-height: 1.2;
}

.diplomas .card {
    border-color: var(--colour-rule-warm);
    border-radius: 20px;
    box-shadow: 0 10px 30px color-mix(in srgb, var(--colour-primary) 5%, transparent);
}

/* The certificate on screen is centred on the page and drawn as the sheet's card; the printed
 * document keeps its own rules (the print block above). */
@media screen {
    .diploma-page {
        margin: 0 auto;
    }

    .diploma-page .diploma {
        border-color: var(--colour-rule-warm);
        border-radius: 20px;
        box-shadow: 0 10px 30px color-mix(in srgb, var(--colour-primary) 5%, transparent);
    }

    .diploma-page > p:last-child {
        margin-top: var(--space-md);
        text-align: center;
    }
}

/* ==========================================================================================
 * SUPPORT TO THE COMPONENT SHEET (items 3 and 10, and the density rules; advisor 2026-10-05 08:40)
 *
 * Every card on the page is the sheet's item 10: white, a hairline, 24px inside (20 on a phone),
 * and an h2 of 22px led by its 40px Ice Blue tile, 12px from the words. The headings were tiled
 * eyebrows in capitals; a card's heading is a heading. The contact box was the ink panel and
 * is now a white card like the v4 target's "Write to support": its rows take the page's ink,
 * and with no address published the box says so as an item-3 fact (.status, the "i").
 * The dates card leaves the tint for the same white. Cards stand 24 apart (16 on a phone).
 * Set LAST, over the Support layers above (novo-css-cascade-traps).
 * ========================================================================================== */
.helpgrid .panel,
.helpgrid .datepanel {
    padding: 24px;
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: 20px;
    background: var(--colour-surface);
}

/* My details' cards take the same heading (consistency round 2026-10-05, item 2). */
.helpgrid .panel__title--tiled,
.profilework .panel__title--tiled {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 0 0 16px;
    color: var(--colour-text);
    font-size: 22px;
    font-weight: var(--font-weight-bold);
    letter-spacing: normal;
    line-height: 1.2;
    text-transform: none;
}

.helpgrid .panel__title--tiled .htile,
.profilework .panel__title--tiled .htile {
    flex: 0 0 40px;
}

.helpgrid,
.helpgrid__answers,
.helpgrid__aside {
    gap: 24px;
}

/* THE CONTACT ROWS ON WHITE: the topic in the page's ink, what it covers in the muted voice, the
 * hairline between them the page's own. */
.helpcontact .helpcontact__lede,
.helpcontact .helpcontact__row,
.helpcontact .helpcontact__address {
    color: var(--colour-text);
}

.helpcontact .helpcontact__about {
    color: var(--colour-text-muted);
}

.helpcontact .helpcontact__row .lineicon {
    color: var(--colour-primary);
}

.helpcontact .helpcontact__route + .helpcontact__route {
    border-top-color: var(--colour-rule-warm);
}

.helpcontact .status {
    margin: 0;
}

/* A date is one line at every width (at 390 "kl. 23:59" broke away from its date). A long label
 * wraps beside it, and where both cannot share the row the value drops whole under its label,
 * so the card never grows past the gutter. */
.helpgrid .datepanel__row {
    flex-wrap: wrap;
}

.helpgrid .datepanel__row dt {
    flex: 1 1 0;
    min-width: min-content;
}

/* A deadline wraps only between its day and its clock (App\Support\Deadline's non-breaking spaces), so the
 * longest one ("torsdag 30. september kl. 23.59") and 200% text stay inside the panel (audit 1006, D9). */
.helpgrid .datepanel__row dd {
    white-space: normal;
}

.helpcontact__note {
    margin: 0;
    font-size: 15px;
    line-height: var(--line-height-base);
}

@media (max-width: 47.9375rem) {
    .helpgrid .panel,
    .helpgrid .datepanel {
        padding: 20px;
    }

    .helpgrid,
    .helpgrid__answers,
    .helpgrid__aside {
        gap: 16px;
    }
}

/* === THE GATE CARDS ON THE COMPONENT SHEET ============================================================
 * Check-email, the expired link and the confirmation (the advisor's nine answers of 2026-10-05 10:00),
 * and the onboarding family — welcome, create a team, join, the join confirmation, find your team
 * (advisor 2026-10-05 13:00) — with /sign-in's measures. Scoped to `.gateshell--sheet`, which those views
 * set, so the split shell's other pages (the dead team link, the administrators' code pages, the error
 * pages) keep theirs. Set LAST: each rule restates a selector an earlier layer styles at the same
 * specificity. */

/* The density table: 16 under the bar and 24 above the footer on a phone, 24 and 32 from the tablet; the
 * card at the top of the content, never centred in empty space. These pages render no footprints. */
.gateshell.gateshell--sheet .gatemain {
    padding-block: 16px 24px;
}

@media (max-width: 47.9375rem) {
    .gateshell.gateshell--sheet .gatemain__inner {
        padding-inline: 16px;
    }
}

@media (min-width: 48rem) {
    .gateshell.gateshell--sheet .gatemain {
        padding-block: 24px 32px;
    }
}

@media (min-width: 64rem) {
    .gateshell.gateshell--sheet .gatemain {
        align-items: flex-start;
    }
}

/* The sheet's card (item 10), at /sign-in's width: 20px corners, 20 inside on a phone and 24 from the
 * tablet, the soft lift. */
.gateshell.gateshell--sheet .gatecard {
    max-width: 35rem;
    padding: var(--card-padding-phone);
    border-radius: var(--radius-2xl);
    box-shadow: 0 10px 30px color-mix(in srgb, var(--colour-primary) 5%, transparent);
}

@media (min-width: 48rem) {
    .gateshell.gateshell--sheet .gatecard {
        padding: var(--card-padding);
    }
}

/* The head: the item-10 tile (40px, a 20px icon) beside the card's title (28, 32 from the tablet); what
 * follows the title — a state, a line — takes the row's whole width under them. */
.gateshell--sheet .gatecard__head,
.gatecard.signin__card .gatecard__head {
    display: grid;
    grid-template-columns: 40px minmax(0, 1fr);
    align-items: center;
    column-gap: 12px;
}

.gateshell--sheet .gatecard__head > *,
.gatecard.signin__card .gatecard__head > * {
    grid-column: 1 / -1;
}

.gateshell--sheet .gatecard__head > .gatecard__icon,
.gatecard.signin__card .gatecard__head > .gatecard__icon {
    grid-column: 1;
    /* Centred on the title's first line, also when the title wraps to two. */
    align-self: start;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    margin: 0;
}

.gateshell--sheet .gatecard__head > .gatecard__icon .lineicon,
.gatecard.signin__card .gatecard__head > .gatecard__icon .lineicon {
    width: 20px;
    height: 20px;
}

/* A card title, not an open page's head (advisor 5/10 11:50): 28 on a phone, 32 from the tablet, the
 * gate family's one size (/sign-in's card the same). Its line is the tile's 40, so the tile stands
 * centred on the first line. */
.gateshell.gateshell--sheet .gatecard .gatecard__head h1,
.gateshell .gatecard.signin__card .gatecard__head h1 {
    grid-column: 2;
    margin: 0;
    font-size: var(--font-size-gate-title-phone);
    font-weight: var(--font-weight-heavy);
    line-height: 40px;
}

@media (min-width: 48rem) {
    .gateshell.gateshell--sheet .gatecard .gatecard__head h1,
    .gateshell .gatecard.signin__card .gatecard__head h1 {
        font-size: var(--font-size-gate-title);
    }
}

.gateshell--sheet .gatecard .gatecard__head .gatecard__lede,
.gatecard.signin__card .gatecard__head .gatecard__lede {
    margin: 6px 0 0;
    font-size: 1.0625rem;
}

/* The state under the expired link's title: the sheet's dot label (item 6), no pill. */
.gateshell--sheet .gatecard__head .gatecard__chip {
    margin: 6px 0 0;
    padding: 0;
    border: 0;
    background: none;
    font-size: 0.8125rem;
    font-weight: var(--font-weight-heavy);
    line-height: 1.4;
}

.gateshell--sheet .gatecard__head .gatecard__chip-dot {
    width: 9px;
    height: 9px;
}

/* THE CARD'S 16 UNDER THE HEAD, given by the head, so whatever follows — a notice, a form, its first
 * label or field — adds none of its own (the onboarding family's forms open with a bare label or a
 * field). Notices keep 16 under them. The label 6 above its field, an error 6 above the field, the hint
 * 6 under it at 13. */
.gateshell--sheet .gatecard .gatecard__head {
    margin-bottom: 16px;
}

.gateshell--sheet .gatecard .throttle-notice,
.gateshell--sheet .gatecard > .status {
    margin: 0 0 16px;
}

.gateshell--sheet .gatecard--mail .checkemail__code {
    margin-top: 0;
}

.gateshell--sheet .gatecard .gatecard__head + .button {
    margin-top: 0;
}

.gateshell.gateshell--sheet .gatecard .gate__form > .gate__label {
    margin: 0 0 6px;
}

.gateshell.gateshell--sheet .gatecard .gate__form .field__input {
    margin-top: 0;
}

.gateshell.gateshell--sheet .gatecard .gate__form .field__error {
    margin: 0 0 6px;
    color: var(--colour-text);
    font-size: 0.875rem;
    font-weight: var(--font-weight-bold);
}

.gateshell.gateshell--sheet .gatecard .gate__form .gate__hint {
    margin: 6px 0 0;
    font-size: 0.8125rem;
    color: var(--colour-text-muted);
}

/* A form of several fields (the onboarding family): 16 between fields, as the card's own gap. Where a
 * field's hint sits between its label and its control, the control and an error stand 6 under it. */
.gateshell.gateshell--sheet .gatecard .gate__form .field {
    margin-top: 16px;
}

.gateshell.gateshell--sheet .gatecard .gate__form .field > .gate__label {
    margin: 0 0 6px;
}

.gateshell.gateshell--sheet .gatecard .gate__form .gate__hint + .field__input,
.gateshell.gateshell--sheet .gatecard .gate__form .gate__hint + .field__error {
    margin-top: 6px;
}

/* The form's first field takes no top margin (the head gave the 16); its action 16 under its last field. */
.gateshell.gateshell--sheet .gatecard .gate__form > div.field:first-of-type {
    margin-top: 0;
}

.gateshell.gateshell--sheet .gatecard .gate__form .button {
    margin-top: 16px;
}

/* A grid of fields keeps one owner of its space: the grid's 16, the fields none (create's placement). */
.gateshell--sheet .gatecard .placegroup__fields {
    gap: 16px;
}

.gateshell.gateshell--sheet .gatecard .gate__form .placegroup__fields .field {
    margin-top: 0;
}

/* A row of actions has its own 16 above it; its buttons add none (the join confirmation's switch). */
.gateshell.gateshell--sheet .gatecard .gate__form .actionrow .button {
    margin-top: 0;
}

/* A hint straight under its label stands 6 below it, as the board draws (the label already gives 6). */
.gateshell.gateshell--sheet .gatecard .gate__form .gate__label + .gate__hint {
    margin-top: 0;
}

/* One mark: the disc. The partials' drawn mark (profile-fields, placement-fields, the find and join
 * forms) is hidden here, so a refusal shows the "!" once (/sign-in drops it in its markup instead). */
.gateshell--sheet .gate__form .field__error-mark {
    display: none;
}

/* The family's in-card blocks (an invitation, a join request, the facts) take the head's 16 above them,
 * not their own 20-32, and the invitation and the request give the card's 16 below them, so what follows
 * - a label, a notice - is never flush. The facts are followed by a form whose action keeps its own 16. */
.gateshell--sheet .gatecard .gatecard__head + :is(.factstile, .invites, .reqcard, .reqcard__withdraw) {
    margin-top: 0;
}

.gateshell--sheet .gatecard > .invites,
.gateshell--sheet .gatecard > .reqcard__withdraw {
    margin-bottom: 16px;
}

/* "Get a new code" is the outlined button (item 4), the sheet's 48, at its own width, 12 under the field. */
.gateshell--sheet .gatecard--mail .checkemail__new {
    margin: 12px 0 0;
}

.gateshell.gateshell--sheet .gatecard--mail .checkemail__new .button {
    width: auto;
    min-height: 48px;
    margin: 0;
    font-size: var(--font-size-base);
}

/* What was asked for, 16 under the action; the foot one quiet line 16 under that, its link the quiet
 * button's bold with the sheet's 3px underline offset. */
.gateshell--sheet .gatecard--mail .checkemail__sent {
    margin-top: 16px;
}

.gateshell--sheet .checkemail__sent .gatecard__lede:first-child {
    margin-top: 0;
}

.gateshell--sheet .checkemail__foot {
    margin: 16px 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    line-height: 1.5;
}

.gateshell--sheet .checkemail__foot .text-link--inline {
    font-weight: var(--font-weight-semibold);
    text-underline-offset: var(--quietlink-underline-offset);
}

/* The confirmation's and the expired link's one action straight under the head's 16 - only there: an
 * action after a field, a facts tile or another action keeps its 16 (find's and create's way elsewhere,
 * the join confirmation's button under its facts). */
.gateshell.gateshell--sheet .gatecard .gate__alternate {
    margin-top: 16px;
}

.gateshell--sheet .gatecard .gatecard__head + .gate__form > input[type="hidden"] + .button,
.gateshell.gateshell--sheet .gatecard .gatecard__head + .gate__alternate {
    margin-top: 0;
}

.gateshell.gateshell--sheet .gatecard .gate__alternate .button {
    margin-top: 0;
}

/* === MY STEPS: A NOT-YET DAY IN A REACHED ROW SHOWS ITS FIELDS DISABLED (sheet item 6; advisor
 * 2026-10-05 13:30) === The fields sit on the card's cool ground with a hairline edge, and the
 * Total band takes the white so it still reads as a band. */
.dtile--future .dtile__input {
    border-color: var(--colour-rule-on-tint);
    background: transparent;
    color: var(--colour-text-muted);
    cursor: not-allowed;
}

.dtile--future .dtile__total {
    background: var(--colour-surface);
    color: var(--colour-text-muted);
}

/* === THE SYSTEM VALUES, APPLIED (the advisor's final consistency round, 2026-10-05 16:20) ===========
 * The values live in tokens.css, one place each. These rules point every role at them, at the
 * specificity of the rule that wins for it today, and set LAST so they win. The pages' structural
 * items (headings beside tiles, the stat row, the dialogs) are their owners' PRs. */

/* The page H1: 34 on a phone, 44 from the tablet, on every participant page (the shared head's
 * title since 2026-10-06, and the diploma page's). */
.pagehead .pagehead__title,
.diplomas__header h1 {
    font-size: var(--font-size-h1-phone);
    line-height: 1.05;
}

@media (min-width: 48rem) {
    .pagehead .pagehead__title,
    .diplomas__header h1 {
        font-size: var(--font-size-h1);
    }
}

/* The eyebrow: one style (its weight the label's emphasis since the weight scale, 2026-10-06). */
.front__eyebrow,
.door__who,
.figband__status,
.invite-panel .invite__alt-heading,
.noteam__eyebrow,
.message__code {
    font-size: var(--font-size-eyebrow);
    font-weight: var(--weight-emphasis);
    letter-spacing: var(--tracking-eyebrow);
    text-transform: uppercase;
}

/* A table's head: one style - small, spaced caps in the quiet grey-blue at 600 (the weight ladder, D1:
 * the head labels its column, it does not compete with it). */
.board-table thead th {
    color: var(--colour-text-muted);
    font-size: var(--font-size-table-head);
    font-weight: var(--weight-emphasis);
    letter-spacing: var(--tracking-table-head);
    text-transform: uppercase;
}

/* The card's padding: 20 on a phone, 24 from the tablet (its corners are --radius-2xl, 20),
 * "everywhere" (16:20). The shared panels and the gate cards read the tokens where they are set
 * (the generic .panel and gate card rules above); here the cards whose winning rule sits elsewhere:
 * the .gate pages (the step confirmation and the administrators' identity page included), the
 * error message, the competitions' cards and the diploma card. */
.gate,
.errorshell .message,
.competitions-v4 .competition,
.diplomacard {
    padding: var(--card-padding-phone);
}

@media (min-width: 48rem) {
    .gate,
    .errorshell .message,
    .competitions-v4 .competition,
    .diplomacard {
        padding: var(--card-padding);
    }
}

/* The status chip beside a page head: a tint pill, an 8px dot (ink a neutral fact, green running
 * or ready) and the word at 14/700. Standings' own .statechip reads the tokens where it is set;
 * here Competitions' "ready" and its neutral fact (item 10), its cards' states (sweep 2, item 10) and
 * the front hero's "counting now" take the same. */
.competitions-v4 .teamrow--ready,
.competitions-v4 .teamrow--neutral,
.competitions-v4 .competition__state,
.front__photo .front__live {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: var(--chip-padding);
    border: 0;
    border-radius: var(--radius-pill);
    background: var(--colour-surface-band);
    color: var(--colour-text);
    font-size: var(--font-size-chip);
    font-weight: var(--font-weight-bold);
}

.competitions-v4 .teamrow--ready .teamrow__dot,
.competitions-v4 .teamrow--neutral .teamrow__dot,
.competitions-v4 .competition__dot,
.front__photo .front__live::before {
    flex: 0 0 var(--chip-dot);
    width: var(--chip-dot);
    height: var(--chip-dot);
    border-radius: 50%;
    background: var(--colour-text);
}

.statechip--live .statechip__dot,
.competitions-v4 .competition__state--running .competition__dot,
.competitions-v4 .teamrow--ready .teamrow__dot,
.front__photo .front__live::before {
    background: var(--colour-success);
}

/* The ready chip's dot is a dot, not a tick. */
.competitions-v4 .teamrow--ready .teamrow__dot::before {
    content: none;
}

/* The quiet link: one style, 15/600, underlined; an SVG arrow where it leads on to another page.
 * A 44px target like every standalone link (--touch-target-min). One that carries the arrow also
 * opts into a.link-standalone (Kenneth, 2026-09-27, item 7: no underline at rest, the arrow is the
 * non-colour cue) and keeps the quiet link's weight and offset. */
.quietlink {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: var(--touch-target-min);
    color: var(--colour-text);
    font-size: var(--font-size-quietlink);
    font-weight: var(--font-weight-semibold);
    text-decoration: underline;
    text-underline-offset: var(--quietlink-underline-offset);
}

.quietlink .lineicon {
    flex: 0 0 16px;
    width: 16px;
    height: 16px;
}

a.quietlink {
    font-weight: var(--font-weight-semibold);
}

a.quietlink:hover,
a.quietlink:focus-visible {
    text-underline-offset: var(--quietlink-underline-offset);
}

/* === THE CONVERTER'S FIELDS ARE ITEM 12'S (sweep 2026-10-05, item 15) ========================
 * "Fields: 48/12 everywhere on participant pages, the converter included" (advisor 16:20). On a
 * laptop the duration, the activity picker and the intensity were 56 tall with 14px corners; they
 * take the sheet's 48 and 12, as a phone already did. The disabled intensity keeps its tint and
 * takes the calm edge every other field wears, not the hairline. The pills' group keeps its height:
 * its pills are touch targets, and 44 of them do not fit inside 48; it takes the 12px corners. The
 * answer ("Konverteret") is an output, not a field, and keeps its own box. */
/* The picker at every width: it joined after the phone's 48 rule and stayed 56 there too. */
.converter .picker__input {
    height: var(--control-height);
    border-radius: var(--control-radius);
}

@media (min-width: 48rem) {
    .converter .field__withunit,
    .converter .field__select {
        height: var(--control-height);
        border-radius: var(--control-radius);
    }

    .converter__choices {
        border-radius: var(--control-radius);
    }

    /* The input inside the duration's box: the box less 3px a side, where its focus ring then
     * stands 3px outside the box, as the phone already draws it. */
    .converter .field__withunit .field__input {
        height: 42px;
        min-height: 0;
    }
}

.converter .field__select:disabled,
.steps-page .converter .field__select:disabled {
    border-color: var(--colour-border-field);
}

/* === B3'S PAGES TO THE CARD PADDING (the final consistency round, 2026-10-05: 24 from the tablet,
 * 20 on a phone, everywhere) === My team's panels, My details' four cards (the side cards were a
 * flat 20 at every width) and the diploma page's two cards. Set last, over their page layers. */
.teamwork .panel,
.profilework .panel,
.diplomas .card {
    padding: var(--card-padding-phone);
}

@media (min-width: 48rem) {
    .teamwork .panel,
    .profilework .panel,
    .diplomas .card {
        padding: var(--card-padding);
    }
}

/* === MY TEAM'S TWO QUIET ACTIONS (advisor 2026-10-05 19:55) =========================================
 * "Send påmindelse" (and "Inviter igen") beside an invitation is the quiet action at every width, as
 * the phone already draws it: the underlined bold word in the page's ink, no border and no pill.
 * Only where the invitations are a table (88rem up): below that the stacked rows' own rule already
 * draws the word, and its padding is what makes the target there (design review: a rule at every
 * width took that padding away and left a 22px target). Here the base rule's 44px min-height keeps
 * it. "Overdrag kaptajnrollen" is the round's arrowed quiet link (.quietlink.link-standalone). */
@media (min-width: 88rem) {
    .roster-panel .roster-table--invites .roster-table__action:not(.roster-table__action--text) {
        padding: 0;
        border: 0;
        background: none;
        color: var(--colour-text);
        font-size: var(--font-size-xs);
        font-weight: var(--font-weight-bold);
        text-decoration: underline;
        text-underline-offset: 3px;
    }
}

/* === THE LAST POLISH (advisor 2026-10-05 21:00), b3's pages ========================================
 * (6) The roster's head is the table head at every width: on a phone its one visible cell, "#", fell
 * back to the base 13/700 at .05em. */
.roster-panel .roster-table thead th {
    font-size: var(--font-size-table-head);
    font-weight: var(--font-weight-heavy);
    letter-spacing: var(--tracking-table-head);
    text-transform: uppercase;
}

/* (4) The deadline card leads with the sheet's tiled h2, as every card on My team; the date under it
 * is the card's value line, 20/700 on one line, then the time and the note. */
.teamwork .deadline-panel {
    display: block;
}

.teamwork .deadline-panel .panel__title {
    margin: 0 0 12px;
}

.teamwork .deadline-panel .deadline-panel__date {
    font-size: 20px;
    font-weight: var(--font-weight-bold);
    line-height: 1.2;
}

/* === MY STEPS' HEAD AS THREE GROUPS (Kenneth 6/10; advisor 2026-10-06 08:15) =========================
 * Dig 1.4 · Kampagnen 0.9 · Dit hold 1.4 across the width, the whole row about 190px tall on a
 * computer so the day grid's top shows at 1440x800. On a phone Dig and Dit hold take the full
 * width with their figures in one row, and Kampagnen is a slim one-line strip.
 * Ink on tint for every bar and meter, no green; line icons in the Ice Blue tiles as everywhere. */
.stepsdash {
    display: grid;
    grid-template-columns: 1.4fr 0.9fr 1.4fr;
    gap: 16px;
    margin: 0;
}

.stepsdash__card {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
    padding: 16px 20px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: var(--radius-2xl);
    background: var(--colour-surface);
}

.stepsdash .stepsdash__title {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 0;
    color: var(--colour-text);
    font-size: 22px;
    font-weight: var(--font-weight-bold);
    line-height: 1.2;
}

.stepsdash__title .htile {
    flex: 0 0 40px;
}

/* Dig: the heading over the chart on the left, the three figures down the right beside both, and
 * the missing line under them across the card (the mockup's arrangement, which keeps the row low). */
.stepsdash .stepsdash__you {
    display: grid;
    grid-template-areas:
        "title figures"
        "bars figures"
        "missing missing";
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
    grid-template-rows: auto 1fr auto;
    gap: 10px 16px;
}

.stepsdash__you > .stepsdash__title {
    grid-area: title;
}

.stepsdash__you > .daybars {
    grid-area: bars;
}

.stepsdash__you > .stepsdash__figures {
    grid-area: figures;
    align-content: center;
}

.stepsdash__you > .stepsdash__missing {
    grid-area: missing;
}

/* The bars: one slot per day, the slot a hairline outline, a saved day's bar filled from the
 * bottom to its share of the best day; today's slot drawn in ink. */
.daybars {
    display: grid;
    grid-auto-columns: minmax(0, 1fr);
    grid-auto-flow: column;
    gap: 4px;
    align-items: end;
    margin: 0;
    padding: 0;
    list-style: none;
}

.daybars__day {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 4px;
    justify-items: stretch;
    min-width: 0;
}

.daybars__slot {
    position: relative;
    display: block;
    height: 52px;
    border: 1px solid var(--colour-rule-warm);
    border-radius: 6px;
}

.daybars__day--saved .daybars__slot {
    border-color: transparent;
}

/* An empty slot must be seen (WCAG 1.4.11, 3:1): the field edge, not the hairline. A day not reached
 * yet is dashed, as the day grid draws a not-yet card, so a gap reads apart from the days ahead. */
.daybars__day--missing .daybars__slot {
    border-color: var(--colour-border-field);
}

.daybars__day--future .daybars__slot {
    border-color: var(--colour-border-field);
    border-style: dashed;
}

.daybars__day--is-today .daybars__slot {
    border: 2px solid var(--colour-text);
}

.daybars__bar {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    display: none;
    border-radius: 5px;
    background: var(--colour-primary);
}

.daybars__day--saved .daybars__bar {
    display: block;
}

.daybars__label {
    display: flex;
    justify-content: center;
    min-height: 14px;
    color: var(--colour-text-muted);
    font-size: 11px;
    line-height: 14px;
    white-space: nowrap;
}

/* With more than seven days only the first and last carry a date; they run outward from their own
 * bar, so a date is never cut to its column's width. */
.daybars__day:first-child .daybars__label {
    justify-content: flex-start;
}

.daybars__day:last-child .daybars__label {
    justify-content: flex-end;
}

.daybars__bar[data-h="0"] { height: 0%; }
.daybars__bar[data-h="5"] { height: 5%; }
.daybars__bar[data-h="10"] { height: 10%; }
.daybars__bar[data-h="15"] { height: 15%; }
.daybars__bar[data-h="20"] { height: 20%; }
.daybars__bar[data-h="25"] { height: 25%; }
.daybars__bar[data-h="30"] { height: 30%; }
.daybars__bar[data-h="35"] { height: 35%; }
.daybars__bar[data-h="40"] { height: 40%; }
.daybars__bar[data-h="45"] { height: 45%; }
.daybars__bar[data-h="50"] { height: 50%; }
.daybars__bar[data-h="55"] { height: 55%; }
.daybars__bar[data-h="60"] { height: 60%; }
.daybars__bar[data-h="65"] { height: 65%; }
.daybars__bar[data-h="70"] { height: 70%; }
.daybars__bar[data-h="75"] { height: 75%; }
.daybars__bar[data-h="80"] { height: 80%; }
.daybars__bar[data-h="85"] { height: 85%; }
.daybars__bar[data-h="90"] { height: 90%; }
.daybars__bar[data-h="95"] { height: 95%; }
.daybars__bar[data-h="100"] { height: 100%; }

.stepsdash__figures {
    display: grid;
    gap: 4px;
    margin: 0;
}

.stepsdash__figures--row {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
}

.stepsdash__value {
    font-size: 18px;
    font-weight: var(--font-weight-heavy);
    font-variant-numeric: tabular-nums;
}

.stepsdash__figures--row .stepsdash__value {
    display: block;
    font-size: 20px;
}

.stepsdash__unit,
.stepsdash__percent {
    color: var(--colour-text-muted);
    font-size: 13px;
}

/* A thin meter, ink on the tint, with its percentage beside it on Dig. */
.meter {
    display: inline-block;
    width: 72px;
    height: 6px;
    margin: 0 6px 0 0;
    overflow: hidden;
    border-radius: 999px;
    background: var(--colour-surface-band);
    vertical-align: middle;
}

.stepsdash__figures--row .meter {
    display: block;
    width: 100%;
    margin: 6px 0 0;
}

.meter__fill {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: var(--colour-primary);
}

.meter__fill[data-w="0"] { width: 0%; }
.meter__fill[data-w="5"] { width: 5%; }
.meter__fill[data-w="10"] { width: 10%; }
.meter__fill[data-w="15"] { width: 15%; }
.meter__fill[data-w="20"] { width: 20%; }
.meter__fill[data-w="25"] { width: 25%; }
.meter__fill[data-w="30"] { width: 30%; }
.meter__fill[data-w="35"] { width: 35%; }
.meter__fill[data-w="40"] { width: 40%; }
.meter__fill[data-w="45"] { width: 45%; }
.meter__fill[data-w="50"] { width: 50%; }
.meter__fill[data-w="55"] { width: 55%; }
.meter__fill[data-w="60"] { width: 60%; }
.meter__fill[data-w="65"] { width: 65%; }
.meter__fill[data-w="70"] { width: 70%; }
.meter__fill[data-w="75"] { width: 75%; }
.meter__fill[data-w="80"] { width: 80%; }
.meter__fill[data-w="85"] { width: 85%; }
.meter__fill[data-w="90"] { width: 90%; }
.meter__fill[data-w="95"] { width: 95%; }
.meter__fill[data-w="100"] { width: 100%; }

/* One quiet line under Dig when days are missing: a small red mark and the words in ink. */
.stepsdash__missing {
    display: inline-flex;
    gap: 8px;
    align-items: center;
    align-self: flex-start;
    min-height: var(--touch-target-min);
    margin: -12px 0 -14px;
    color: var(--colour-text);
    font-size: 14px;
    font-weight: var(--font-weight-bold);
    text-decoration: none;
}

.stepsdash__missing:hover,
.stepsdash__missing:focus-visible {
    text-decoration: underline;
    text-underline-offset: 3px;
}

.stepsdash__missing-mark {
    display: inline-grid;
    flex: 0 0 18px;
    width: 18px;
    height: 18px;
    place-items: center;
    border-radius: 50%;
    background: var(--colour-danger);
    color: var(--colour-surface);
    font-size: 12px;
    font-weight: var(--font-weight-heavy);
}

/* Kampagnen: the eyebrow, the day large and centred, the segments, the week and the period. */
.stepsdash__campaign {
    position: relative;
    align-items: center;
    justify-content: center;
    gap: 10px;
    text-align: center;
}

.stepsdash__day {
    margin: 0;
    color: var(--colour-text);
    font-size: 40px;
    font-weight: var(--font-weight-heavy);
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.stepsdash__day--state {
    font-size: 22px;
}

.stepsdash__day-short {
    display: none;
}

.stepsdash__when {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: 13px;
}

.stepsdash__empty-heading {
    margin: 0;
    color: var(--colour-text);
    font-weight: var(--font-weight-bold);
}

@media (min-width: 48rem) and (max-width: 63.9375rem) {
    .stepsdash {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    .stepsdash__campaign {
        grid-column: 1 / -1;
        grid-row: 1;
    }
}

/* On a phone: Dig and Dit hold full width, their figures in one row; Kampagnen one slim line. */
@media (max-width: 47.9375rem) {
    .stepsdash {
        grid-template-columns: minmax(0, 1fr);
        gap: 12px;
    }

    .stepsdash__card {
        gap: 8px;
        padding: 12px 16px;
    }

    /* The phone's tiles and titles at the stat row's phone size (32px, 18px), so three groups stay
     * shorter than the four cards they replaced and the day strip keeps its place above the fold. */
    .stepsdash .stepsdash__title {
        gap: 10px;
        font-size: 18px;
    }

    .stepsdash__title .htile {
        flex-basis: 32px;
        width: 32px;
        height: 32px;
    }

    .stepsdash__title .htile .lineicon {
        width: 16px;
        height: 16px;
    }

    .stepsdash .stepsdash__you {
        gap: 8px;
    }

    .stepsdash__unit,
    .stepsdash__percent {
        font-size: 12px;
    }

    .stepsdash .stepsdash__you {
        grid-template-areas:
            "title"
            "bars"
            "figures"
            "missing";
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto;
    }

    .daybars__slot {
        height: 22px;
    }

    /* The day strip right under the head carries the dates, so the chart drops its own here. */
    .daybars__label {
        display: none;
    }

    .stepsdash__campaign {
        flex-direction: row;
        gap: 12px;
        padding: 12px 16px;
        text-align: left;
    }

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

    .stepsdash__day {
        flex: 0 0 auto;
        font-size: 20px;
    }

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

    .stepsdash__day-short {
        display: inline;
    }

    .stepsdash__figures--row .stepsdash__value {
        font-size: 16px;
    }
}

/* ON A PHONE, DIT HOLD AND THE "i" LINE COME AFTER TODAY'S DAY CARD (advisor 2026-10-06 10:20): Dig and
 * the Kampagnen strip stay on top, and today's fields are back above the fold. The dashboard's box is
 * flattened into the page's column so its cards can be ordered there; the converter stays last. */
@media (max-width: 47.9375rem) {
    .pagestack > .stepsdash {
        display: contents;
    }

    /* Kampagnedag joins Dit hold after today's card on a phone (My steps v2, measured in a real
     * 390x740 viewport: with it on top, today's field sat under the fixed tab bar at 658). */
    .pagestack > .stepsdash > .stepsdash__team,
    .pagestack > .stepsdash > .stepsdash__campaign {
        order: 1;
    }

    .pagestack > .converter {
        order: 2;
    }
}

/* === A TABLE'S TWO ENDS (Kenneth, 2026-10-06 08:00) ==========================================
 * The first cell's left and the last cell's right take the same 16 inside, so a highlighted row's
 * two ends are symmetric and a number never touches the row's edge (Standings' own row showed
 * "23 390" flush against it, the last cell having none). Where a list is stacked into two-line rows
 * on a narrower screen, the row itself keeps the 16 at both ends instead. The admin tables are in
 * admin.css. */
.board-table:not(.supportlist) :is(th, td):first-child {
    padding-left: var(--space-sm);
}

.board-table:not(.supportlist) :is(th, td):last-child {
    padding-right: var(--space-sm);
}

/* On a phone the board hides its wide columns, and on Personligt the last one is wide: the cell
 * before it is then the row's last, and takes the 16. */
@media (max-width: 47.99rem) {
    .board-table:not(.supportlist) :is(th, td):has(+ .board-table__wide:last-child) {
        padding-right: var(--space-sm);
    }

    /* And the own row's and the head's rounded end with it, so both ends match. */
    .board-panel .board-table__row--you > :has(+ .board-table__wide:last-child) {
        border-radius: 0 12px 12px 0;
    }

    .board-table thead tr th:has(+ .board-table__wide:last-child) {
        border-start-end-radius: var(--radius-lg);
        border-end-end-radius: var(--radius-lg);
    }

    /* The 16 at the far end is paid for by the rank column, not the name: 64 rather than 72 (16,
     * the 36 place circle and 8 more at 390), so the line under a team's name ("3 medlemmer ·
     * 71 % indtastet") keeps to one line. */
    .board-table:not(.supportlist) tr:not(.board-table__gap) > :is(th, td):first-child {
        width: 4rem;
        padding-right: var(--space-2xs);
    }
}

@media (min-width: 80rem) {
    .roster-panel .roster-table:not(.roster-table--invites) :is(th, td):first-child {
        padding-left: var(--space-sm);
    }

    .roster-panel .roster-table:not(.roster-table--invites) :is(th, td):last-child {
        padding-right: var(--space-sm);
    }
}

@media (max-width: 79.999rem) {
    .roster-panel .roster-table:not(.roster-table--invites) .roster-table__row {
        padding-inline: var(--space-sm);
    }
}

@media (min-width: 88rem) {
    .roster-panel .roster-table--invites :is(th, td):first-child {
        padding-left: var(--space-sm);
    }

    .roster-panel .roster-table--invites :is(th, td):last-child {
        padding-right: var(--space-sm);
    }
}

@media (max-width: 87.999rem) {
    .roster-panel .roster-table--invites .roster-table__row {
        padding-inline: var(--space-sm);
    }
}

/* === A SAVED DAY IS UNMISTAKABLY DONE (Kenneth 6/10; advisor 2026-10-06 11:30) =======================
 * The computer's tile, the phone's day card and its chip in the strip take the soft green ground and
 * a green top edge; the check stays beside "Gemt". Missing keeps its red edge and dot, today its blue.
 * A day edited and not yet saved (.is-unsaved) loses the green until it is saved again. The Dig
 * chart's bars stay ink: the cards carry the green. */
/* TODAY STAYS BLUE (advisor 11:30), so a saved today keeps its own ground and lift; and the chip the
 * strip has selected stays ink, its words white (design review: white on the green was unreadable). */
.dtile--saved:not(.is-unsaved):not(.dtile--is-today),
.daycard--saved:not(.is-unsaved):not(.daycard--is-today),
.daychip--saved:not(.is-unsaved):not([aria-current="true"]) {
    background: var(--steps-saved-ground);
}

.dtile--saved:not(.is-unsaved):not(.dtile--is-today) {
    border-color: transparent;
    box-shadow: inset 0 0 0 2px var(--steps-saved-edge);
}

/* The day card keeps the card's lift under its green edge. */
.daycard--saved:not(.is-unsaved):not(.daycard--is-today) {
    border-color: transparent;
    box-shadow: inset 0 0 0 2px var(--steps-saved-edge), var(--shadow-md);
}

.daychip--saved:not(.is-unsaved):not([aria-current="true"]) {
    border-color: transparent;
    box-shadow: inset 0 0 0 2px var(--steps-saved-edge);
}

.daycard--saved:not(.is-unsaved) .daycard__status::before {
    content: "✓ ";
    content: "✓ " / "";
    color: var(--colour-success);
}

/* === THE SHARED PAGE HEAD AND SHELL (Kenneth, 2026-10-06: "the page jumps between tabs") =========
 * My steps, Standings, Competitions, My details, Support and My team draw one head: the H1 and, on its
 * line, a status chip or the team's Rename if there is one; one lede line under it; no eyebrow (the day
 * and the period live in the dashboards and the chips); the trail at the head's far edge, taking no
 * room. Measured: the H1's x and y and the content's left edge are the same on all six, at 1440 and
 * 390 (docs/task-briefs/shared-page-shell.md).
 *
 * The scrollbar's room is kept on every page, so a short page and a long one start at the same x. */
html {
    scrollbar-gutter: stable;
}

.pagehead {
    position: relative;
    display: block;
    min-height: 0;
    margin: 0;
    padding: 0;
}

.pagehead .pagehead__titlerow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2xs) var(--space-sm);
    min-height: 0;
    margin: 0;
}

.pagehead .pagehead__title {
    margin: 0;
    color: var(--colour-text);
    font-weight: var(--font-weight-heavy);
    letter-spacing: -0.02em;
}

.pagehead .pagehead__lede {
    max-width: 60ch;
    margin: var(--space-2xs) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-base);
    line-height: 1.45;
}

/* A chip on the title's line sits on its middle and keeps its own size. Not My team's Rename: open,
 * it takes its own full row under the title (.pagehead--team .rename[open]), so the title stays put. */
.pagehead .pagehead__titlerow > :not(.pagehead__title):not(.rename) {
    flex: none;
    margin: 0;
}

/* The count band Competitions keeps under the head is spaced by the page stack alone. */
.competitions-v4 > .teamrow {
    margin-top: 0;
}

/* The trail takes no room: placed at the head's far edge, as My steps' was. */
.pagehead .trail {
    position: absolute;
    top: 0;
    right: 0;
    pointer-events: none;
}

/* Where the trail shows, the words keep clear of it. */
@media (min-width: 56.25rem) {
    .pagehead .pagehead__intro {
        padding-right: 360px;
    }
}

/* Sections 24 apart on every tab (16 on a phone). */
.pagestack {
    gap: 24px;
}

@media (max-width: 47.9375rem) {
    .pagestack {
        gap: 16px;
    }
}

/* === MY STEPS V2, DRAWN LIKE THE MOCKUP (Kenneth 6/10; advisor 2026-10-06 13:45, design freedom 13:50)
 * Rich, tinted, readable at a glance. Outside the guide by Kenneth's decision for this page:
 * tinted cards with white figure tiles, Forest Green for "entered" (the chart's bars, the meters,
 * the saved day), and a state ground on every day card. Text stays Lasting Blue and AA on each. */

/* The three groups: the page's tint, no hairline, and room for their tiles. */
.stepsdash {
    gap: 16px;
}

.stepsdash .stepsdash__card {
    gap: 12px;
    padding: 18px 20px;
    border: 0;
    background: var(--colour-surface-band);
}

.stepsdash .stepsdash__title {
    font-size: 20px;
    font-weight: var(--font-weight-heavy);
}

.stepsdash .stepsdash__title--centred {
    justify-content: center;
    font-size: 17px;
}

/* Dig: the heading over the chart on the left, the tiles on the right, the missing line under. */
.stepsdash .stepsdash__you {
    grid-template-areas:
        "title figures"
        "bars figures"
        "missing missing";
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.3fr);
    grid-template-rows: auto 1fr auto;
    gap: 10px 16px;
}

/* The chart: bars, not squares - at most 30 wide, 8 apart, bottom-aligned on a 100px height, with
 * rounded tops; a day with nothing on it a short outlined slot, today's in ink. */
.stepsdash .daybars {
    grid-auto-columns: minmax(0, 30px);
    gap: 8px;
    align-self: end;
    justify-content: start;
}

.stepsdash .daybars:has(> :nth-child(8)) {
    gap: 3px;
}

.stepsdash .daybars__slot {
    height: 18px;
    border: 1.5px solid var(--colour-border-field);
    border-radius: 6px;
    background: var(--colour-surface);
}

.stepsdash .daybars__day--future .daybars__slot {
    border-style: dashed;
}

.stepsdash .daybars__day--is-today .daybars__slot {
    border: 2px solid var(--colour-text);
}

.stepsdash .daybars__day--saved .daybars__slot {
    height: 100px;
    border-color: transparent;
    background: transparent;
}

.stepsdash .daybars__day--saved.daybars__day--is-today .daybars__slot {
    border-color: transparent;
}

.stepsdash .daybars__bar {
    border-radius: 7px 7px 3px 3px;
    background: var(--colour-success);
}

.stepsdash .daybars__day--saved.daybars__day--is-today .daybars__bar {
    box-shadow: 0 0 0 2px var(--colour-surface-band), 0 0 0 4px var(--colour-text);
}

.stepsdash .daybars__label {
    font-size: 11px;
}

/* The figures as white tiles: a line icon in a tint circle, the number, its words under it. */
.stepsdash .stepsdash__figures {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}

.stepsdash .stepsdash__figures--row {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.ministat {
    min-width: 0;
}

.ministat--wide {
    grid-column: 1 / -1;
}

.ministat dd {
    display: grid;
    grid-template-columns: 30px minmax(0, 1fr);
    column-gap: 10px;
    align-content: center;
    align-items: center;
    height: 100%;
    margin: 0;
    padding: 10px 12px;
    border-radius: 14px;
    background: var(--colour-surface);
    color: var(--colour-text);
    font-size: 13px;
    line-height: 1.25;
}

.ministat__icon {
    display: inline-grid;
    grid-row: 1 / span 3;
    width: 30px;
    height: 30px;
    place-items: center;
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-text);
}

.ministat__icon .lineicon {
    width: 16px;
    height: 16px;
}

.ministat dd > .stepsdash__value {
    grid-column: 2;
    display: block;
    font-size: 19px;
    line-height: 1.15;
}

.ministat dd > .stepsdash__unit {
    grid-column: 2;
    color: var(--colour-text-muted);
    font-size: 12px;
}

.ministat dd > :not(.ministat__icon):first-child {
    grid-column: 1 / -1;
}

.ministat__meter,
.ministat dd > .meter {
    grid-column: 2;
    display: flex;
    gap: 6px;
    align-items: center;
    margin-top: 6px;
}

.ministat .meter {
    flex: 1 1 auto;
    width: auto;
    height: 6px;
    margin: 0;
    background: var(--colour-surface-band);
}

.ministat .meter__fill {
    background: var(--colour-success);
}

.ministat .stepsdash__percent {
    font-size: 12px;
}

.stepsdash .stepsdash__team-name {
    display: flex;
    gap: 10px;
    align-items: center;
    margin: -4px 0 0;
    color: var(--colour-text);
    font-size: 16px;
    font-weight: var(--font-weight-bold);
    overflow-wrap: anywhere;
}

/* Kampagnedag: sentence case, the day large, then the segments and the week. */
.stepsdash .stepsdash__campaign {
    gap: 8px;
}

.stepsdash .stepsdash__day {
    font-size: 44px;
}

/* The days: the week under the heading, a legend of dots, and a ground for every state. */
.days__heading {
    display: grid;
    gap: 2px;
}

.days__heading .days__range {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: 15px;
    font-weight: var(--font-weight-regular);
}

.days__legend .mark--saved {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--colour-success);
    font-size: 0;
    vertical-align: middle;
}

.days__legend .mark--today {
    display: inline-block;
    width: 10px;
    height: 10px;
    border: 2px solid var(--colour-text);
    border-radius: 50%;
    background: var(--steps-today-ground);
    vertical-align: middle;
}

.dtile--missing:not(.is-unsaved),
.daycard--missing:not(.is-unsaved),
.daychip--missing:not(.is-unsaved):not([aria-current="true"]) {
    border-color: transparent;
    background: var(--steps-missing-ground);
    box-shadow: inset 0 0 0 2px var(--steps-missing-edge);
}

.daycard--missing:not(.is-unsaved) {
    box-shadow: inset 0 0 0 2px var(--steps-missing-edge), var(--shadow-md);
}

.dtile--is-today {
    outline-width: 2px;
    outline-offset: -2px;
}

.dtile--future,
.daychip--future {
    border-style: solid;
    border-color: transparent;
    background: color-mix(in srgb, var(--colour-text-muted) 7%, var(--colour-surface));
}

/* Save and one line beside it: when today counts, or the quiet confirmation after a save. */
.days__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px 20px;
    align-items: center;
}

.days__note {
    display: inline-flex;
    gap: 8px;
    align-items: center;
    margin: 0;
    color: var(--colour-text-muted);
    font-size: 15px;
}

.days__note--saved {
    padding: 8px 14px;
    border-radius: 999px;
    background: var(--steps-saved-ground);
    color: var(--colour-text);
    font-weight: var(--font-weight-bold);
}

.days__note--saved .days__note-detail {
    font-weight: var(--font-weight-regular);
}

.days__note-mark {
    display: inline-grid;
    flex: 0 0 22px;
    width: 22px;
    height: 22px;
    place-items: center;
    border-radius: 50%;
    background: var(--colour-success);
    color: var(--colour-surface);
}

.days__note-mark .lineicon {
    width: 14px;
    height: 14px;
}

/* SAVE ABOVE THE FOLD AT 1440x800, the one fixed rule (advisor 13:50): Dig takes the width its tiles
 * need, the chart is 80 tall, and the days' card, its head and each day are a little denser. */
@media (min-width: 64rem) {
    .stepsdash {
        grid-template-columns: 1.6fr 0.6fr 1.45fr;
    }
}

/* Dit hold's three tiles each say their words on one line at a computer's width (design review:
 * wrapped labels made the team side denser than Dig and ate Save's margin). */
@media (min-width: 64rem) {
    .stepsdash__team .ministat dd {
        grid-template-columns: 26px minmax(0, 1fr);
        column-gap: 8px;
        padding: 8px 10px;
    }

    .stepsdash__team .ministat__icon {
        width: 26px;
        height: 26px;
    }

    .stepsdash__team .ministat dd > .stepsdash__unit:not(.stepsdash__unit--empty) {
        white-space: nowrap;
    }
}

.stepsdash .stepsdash__card {
    padding: 12px 18px;
}

.stepsdash .stepsdash__you {
    row-gap: 8px;
}

.stepsdash .daybars__day--saved .daybars__slot {
    height: 72px;
}

.ministat dd > .stepsdash__value {
    white-space: nowrap;
}

.ministat dd {
    padding: 8px 12px;
}

@media (min-width: 48rem) {
    .card.days__card--desk {
        gap: 10px;
        padding: 16px 24px;
    }

    .days__card--desk .days__title {
        line-height: 1.15;
    }

    .days__card--desk .days__heading .days__range {
        line-height: 1.3;
    }

    .days__card--desk .dtile {
        gap: 4px;
        padding: 10px 12px;
    }

    .days__card--desk .dtile__input {
        height: 38px;
    }

    .days__card--desk .dtile__total {
        padding: 6px 10px;
    }
}

/* The phone: Dig's three tiles in one row under the chart, the team's three likewise. */
@media (max-width: 47.9375rem) {
    .stepsdash .stepsdash__you {
        grid-template-areas:
            "title"
            "bars"
            "figures"
            "missing";
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto;
    }

    .stepsdash .stepsdash__figures {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 6px;
    }

    .ministat--wide {
        grid-column: auto;
    }

    .ministat dd {
        grid-template-columns: minmax(0, 1fr);
        padding: 8px;
    }

    .ministat dd > * {
        grid-column: 1;
    }

    .ministat__icon {
        display: none;
    }

    .ministat dd > .stepsdash__value {
        font-size: 15px;
    }

    .ministat dd > .stepsdash__unit {
        font-size: 11px;
    }

    .stepsdash .daybars__day--saved .daybars__slot {
        height: 44px;
    }

    .stepsdash .daybars__slot {
        height: 12px;
    }

    .stepsdash .daybars {
        justify-content: stretch;
        grid-auto-columns: minmax(0, 1fr);
    }

    .days__actions .days__note {
        width: 100%;
    }

    /* Kampagnedag on a phone is the one-line strip: its heading said to the ear, the short day and
     * the segments to the eye. */
    .stepsdash .stepsdash__campaign .stepsdash__title {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .stepsdash .stepsdash__campaign .stepsdash__day {
        font-size: 20px;
    }
}

/* === MY STEPS V2, THE DESIGN REVIEW'S ROUND ==========================================================
 * The chart fills Dig's left half: one column per day, each bar at most 32 wide and centred in it;
 * an empty day is a short flat tab, never a ring that reads as a zero. */
.stepsdash .daybars {
    grid-auto-columns: minmax(0, 1fr);
    justify-content: stretch;
}

.stepsdash .daybars__slot {
    justify-self: center;
    width: min(100%, 32px);
    height: 10px;
    border-width: 1.5px;
    border-radius: 3px;
}

.stepsdash .daybars:has(> :nth-child(8)) .daybars__day:not(.daybars__day--saved) .daybars__slot {
    height: 6px;
    border-radius: 2px;
}

/* Kampagnedag's heading on the same line as Dig's and Dit hold's; the figure group centred under it. */
.stepsdash .stepsdash__campaign {
    justify-content: flex-start;
}

.stepsdash .stepsdash__campaign .stepsdash__day {
    margin-top: auto;
}

.stepsdash .stepsdash__campaign .stepsdash__when {
    margin-bottom: auto;
}

/* The day cards' status words lead with the legend's marks: a filled green check for Gemt, an ink
 * ring for I dag. The words still say the state. */
.dtile--saved:not(.is-unsaved) .dtile__status::before,
.daycard--saved:not(.is-unsaved) .daycard__status::before {
    content: "✓";
    content: "✓" / "";
    display: inline-grid;
    width: 16px;
    height: 16px;
    margin-right: 6px;
    place-items: center;
    border-radius: 50%;
    background: var(--colour-success);
    color: var(--colour-surface);
    font-size: 10px;
    line-height: 1;
    vertical-align: -3px;
}

.dtile--today:not(.is-unsaved) .dtile__status::before,
.daycard--today:not(.is-unsaved) .daycard__status::before {
    content: "";
    display: inline-block;
    width: 10px;
    height: 10px;
    margin-right: 6px;
    border: 2px solid var(--colour-text);
    border-radius: 50%;
    vertical-align: -1px;
}

@media (max-width: 47.9375rem) {
    /* Dig's days-entered meter keeps its width on a phone, beside its %. */
    .ministat .ministat__meter {
        display: flex;
        width: 100%;
    }

    .ministat .ministat__meter .meter {
        flex: 1 1 24px;
        min-width: 24px;
    }

    /* Dig a little lower on a phone, so today's field keeps its margin above the fold. */
    .stepsdash .daybars__day--saved .daybars__slot {
        height: 32px;
    }

    .stepsdash .daybars__slot {
        height: 8px;
    }

    .ministat dd {
        padding: 6px 8px;
    }

    /* One column on a phone for every part of a tile: the computer's rule that puts the number and
     * its words beside the icon (column 2) would otherwise open a second column here. */
    .ministat dd > .stepsdash__value,
    .ministat dd > .stepsdash__unit,
    .ministat dd > .ministat__meter,
    .ministat dd > .meter {
        grid-column: 1;
    }

    /* Bars on a phone, not squares: narrow and taller than wide. */
    .stepsdash .daybars__slot {
        width: min(100%, 16px);
    }

    /* Dig compact enough on a phone that today's field clears the fixed tab bar (measured at a
     * real 390x740: the bar's top is at 658). */
    .stepsdash .stepsdash__card {
        padding: 12px 14px;
    }

    .stepsdash .stepsdash__you {
        row-gap: 6px;
    }

    .stepsdash .daybars__day--saved .daybars__slot {
        height: 26px;
    }

    .ministat dd > .stepsdash__unit {
        line-height: 1.2;
    }
}

/* === MY STEPS V2, QUIETER (the designer's review; advisor 2026-10-06 15:35) =========================
 * One order of attention: today's day card, then Save, then the campaign day. Everything else steps
 * down - semibold rather than heavy, grey-blue words, thinner lines - and Dig reads as a small bar
 * chart: narrow green bars on a faint baseline, an empty day a low stub. */
.stepsdash .stepsdash__title,
.stepsdash .stepsdash__title--centred {
    font-size: 17px;
    font-weight: var(--font-weight-bold);
}

.stepsdash .stepsdash__team-name {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
}

.ministat dd > .stepsdash__value {
    font-weight: var(--font-weight-semibold);
}

.ministat dd > .stepsdash__unit,
.ministat .stepsdash__percent {
    font-weight: var(--font-weight-regular);
}

@media (min-width: 48rem) {
    .ministat dd > .stepsdash__value {
        font-size: 18px;
    }

    .ministat dd {
        grid-template-columns: 26px minmax(0, 1fr);
    }
}

.ministat__icon {
    width: 26px;
    height: 26px;
}

.ministat__icon .lineicon {
    width: 14px;
    height: 14px;
}

.ministat .meter {
    height: 4px;
}

/* The chart. Every day's column carries a faint baseline under its slot (it runs on through the gap,
 * so the line is unbroken); the label row under it is 14px plus the day's 4px gap. */
.stepsdash .daybars__day {
    position: relative;
}

.stepsdash .daybars__day::before {
    content: "";
    position: absolute;
    right: -4px;
    bottom: 17px;
    left: -4px;
    height: 1px;
    background: color-mix(in srgb, var(--colour-border-field) 35%, transparent);
}

.stepsdash .daybars .daybars__slot {
    width: min(100%, 22px);
}

.stepsdash .daybars .daybars__day:not(.daybars__day--saved) .daybars__slot,
.stepsdash .daybars:has(> :nth-child(8)) .daybars__day:not(.daybars__day--saved) .daybars__slot {
    height: 4px;
    border: 0;
    border-radius: 2px;
    /* A day ahead is the field edge itself (about 4:1 on the band, WCAG 1.4.11): quiet by being
     * low, not by being faint. */
    background: var(--colour-border-field);
}

/* "I alt" stays one word beside a six-figure total at 1024. */
.dtile__total > :first-child {
    white-space: nowrap;
}

.stepsdash .daybars .daybars__day--missing:not(.daybars__day--saved) .daybars__slot.daybars__slot {
    background: var(--colour-danger);
}

.stepsdash .daybars .daybars__day--today:not(.daybars__day--saved) .daybars__slot.daybars__slot {
    background: var(--colour-text);
}

/* The day cards: today is the strongest (its ink ring and a lift), saved a clear green, missing a
 * thinner soft red; the words around the fields step down to semibold and regular. */
.dtile--missing:not(.is-unsaved),
.daychip--missing:not(.is-unsaved):not([aria-current="true"]) {
    box-shadow: inset 0 0 0 1.5px var(--steps-missing-edge);
}

.daycard--missing:not(.is-unsaved) {
    box-shadow: inset 0 0 0 1.5px var(--steps-missing-edge), var(--shadow-md);
}

.dtile__when b,
.daycard__title {
    font-weight: var(--font-weight-semibold);
}

.dtile__status,
.daycard__status {
    font-weight: var(--font-weight-semibold);
}

.dtile__label,
.daycard__label {
    color: var(--colour-text-muted);
    font-weight: var(--font-weight-regular);
}

.dtile__total,
.daycard__total {
    font-weight: var(--font-weight-regular);
}

.dtile__total b,
.daycard__total b {
    font-weight: var(--font-weight-semibold);
}

.days__legend {
    font-size: 13px;
}

.days__note--saved {
    font-weight: var(--font-weight-semibold);
}

/* The converter: every control 48 tall on one baseline - the activity, the duration, the question
 * (its pills inside a 48px frame), the equals and the answer, whose edge is a field's, not a bar. */
.steps-page .converter__equals {
    line-height: 48px;
}

@media (min-width: 64rem) {
    .steps-page .converter__result-label {
        margin-bottom: 7px;
    }
}

.steps-page .converter__result-value {
    height: 48px;
    min-height: 48px;
    border-width: 1.5px;
    border-radius: 10px;
    font-size: 24px;
    font-weight: var(--font-weight-semibold);
}

/* "Vælg først en aktivitet" (advisor 15:45) needs 230 where the column was 180 for a select. */
@media (min-width: 48rem) and (max-width: 79.9375rem) {
    .converter__row:not(:has(.converter__choices)) {
        grid-template-columns: 1fr 120px 232px;
    }
}

@media (min-width: 80rem) {
    .converter__row .converter__field--qualifier:not(:has(.converter__choices)) {
        flex: 0 0 232px;
    }
}

.converter__choice-label {
    min-height: 38px;
    font-weight: var(--font-weight-semibold);
}

@media (max-width: 47.9375rem) {
    .stepsdash .daybars .daybars__slot {
        width: min(100%, 14px);
    }

    /* The phone's chart has no date row (the day strip under it carries the dates). */
    .stepsdash .daybars__day::before {
        bottom: 0;
    }
}

/* No figure or label wraps badly at 1024 or 1280 (the designer's shot broke "skridt tæller i /
 * stillingen"): below 1440 the three groups do not fit one row (measured: at 1366 a 14-day campaign
 * broke "11 / 14" and Dig's labels), so Dig and Kampagnedag share the first and Dit hold takes the
 * full width under them. At 1440 Dig's tiles get the larger share of its card and say each label on
 * one line. */
/* The running day's figure only: the not-running sentence ("Starter 30. september") may wrap, and
 * is a sentence at a heading's size, not a 44px figure broken over three lines. */
.stepsdash .stepsdash__day:not(.stepsdash__day--state) {
    white-space: nowrap;
}

.stepsdash .stepsdash__campaign .stepsdash__day--state {
    font-size: 20px;
    font-weight: var(--font-weight-bold);
    line-height: 1.25;
    text-align: center;
}

@media (min-width: 90rem) {
    .stepsdash .stepsdash__you {
        grid-template-columns: minmax(0, 0.75fr) minmax(0, 1.45fr);
    }

    .stepsdash__you .ministat dd {
        padding-inline: 10px;
    }

    /* A figure's short label stays on one line; the empty states' sentences ("Ingen afsluttede
     * dage endnu") are longer than a tile and wrap instead of running out of it. */
    .stepsdash__you .ministat dd > .stepsdash__unit:not(.stepsdash__unit--empty) {
        white-space: nowrap;
    }
}

@media (min-width: 64rem) and (max-width: 89.9375rem) {
    .stepsdash {
        grid-template-columns: minmax(0, 1.7fr) minmax(0, 0.6fr);
    }

    /* One compact row, so the lowest-priority group does not push Save down a laptop's screen: the
     * heading and the team's name on the left, the three tiles beside them. */
    .stepsdash .stepsdash__team {
        display: grid;
        grid-column: 1 / -1;
        grid-template-columns: max-content minmax(0, 1fr);
        column-gap: 24px;
        row-gap: 4px;
        align-items: center;
    }

    .stepsdash__team > .stepsdash__title {
        grid-column: 1;
        grid-row: 1;
    }

    .stepsdash .stepsdash__team > .stepsdash__team-name {
        grid-column: 1;
        grid-row: 2;
        margin: 0;
    }

    .stepsdash__team > .stepsdash__figures {
        grid-column: 2;
        grid-row: 1 / span 2;
    }
}

/* === PERFECTLY ALIGNED (Kenneth's designer, 2026-10-06) =========================================
 * Measured from the glyphs' ink at 4x: this face set capitals and figures about 1.2px above a box's
 * centre - the Standings tabs' "Danmark" 1.25 high, "Mit holds EVP-område" 1.9, the rank circles
 * 0.5-1.5, Competitions' ready chip 1.0.
 *
 * In a pill of fixed height the tall line box was the cause: centred at line-height 1 the label lands
 * on its optical centre ("Danmark" -0.25, measured), so the pills take line-height 1 and nothing more.
 * A circle or a chip, whose height comes from its padding and line, also moves its label down by
 * --optical-nudge (tokens.css). */

/* 1. Segmented controls and pills: the label centred at line-height 1; Standings' tabs and filters one
 * height, the 44 touch target. The language switch keeps its own heights. The converter's controls are
 * b3's (the My steps amendment sets them all to 48 on one baseline), so they are not touched here. */
.boardtabs__tab,
.language__current,
.language__choice {
    align-items: center;
    line-height: 1;
}

.boardtabs__tab {
    min-height: var(--touch-target-min);
}

/* The chips keep their height (their padding and the body's line), so the label moves within it. Not
 * the competition cards' state chips: measured already centred ("Kører nu" 0.0), a nudge made them low. */
.statechip,
.competitions-v4 .teamrow--ready,
.competitions-v4 .teamrow--neutral,
.front__photo .front__live {
    padding-top: calc(var(--chip-padding-block) + var(--optical-nudge));
    padding-bottom: calc(var(--chip-padding-block) - var(--optical-nudge));
}

/* 2. The rank circles: the figures exactly on the circle's centre, tabular. */
.board-table__pos {
    /* The circle's figures are larger, so half the pill's move (measured: 0.5-1.1px low at twice). */
    padding-top: var(--optical-nudge);
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

/* The medals' smaller figures move half as far again (measured: 0.5 low with the plain circles' move). */
.board-table .board-table__pos--medal {
    padding-top: calc(var(--optical-nudge) / 2);
}

/* 3. The No. column: the circles, the plain numbers and the not-ranked dash on one centre line, in the
 * column's fixed width. */
.board-table:not(.supportlist) :is(th, td):first-child {
    text-align: center;
}

/* 4. The figure columns: right-aligned and tabular, the dash in the same right edge as the numbers,
 * each head on its column's edge. */
.board-table .board-table__figure {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* === LÆG TIL DAGEN (advisor 2026-10-06 15:35) ====================================================
 * Under the calculator's row, on its own hairline: the label, then the day and "Læg til" on one
 * line, both the row's 48; the quiet line after it says what was added and to remember Save. On a
 * phone the day takes the width and the button sits beside it. */
.converter__addto {
    display: grid;
    gap: 8px;
    margin-top: 4px;
    padding-top: 16px;
    border-top: var(--border-width) solid var(--colour-rule-on-tint);
}

.converter__addto[hidden] {
    display: none;
}

.converter__addto-row {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
}

.converter__addto .converter__addto-day {
    flex: 0 1 240px;
    min-width: 0;
    height: 48px;
}

.converter__addto .converter__addto-button {
    min-height: 48px;
    padding-inline: 24px;
}

.converter__addto-status {
    min-height: 1.4em;
    margin: 0;
    color: var(--colour-text);
    font-size: 15px;
}

@media (max-width: 47.9375rem) {
    .converter__addto .converter__addto-day {
        flex: 1 1 0;
    }
}

/* === MY STEPS, THE TILES' POLISH (advisor 2026-10-06 17:45) =======================================
 * 1. Every tile's figure on one line across its row: the figure and its words from the tile's top,
 *    the meter under the words (a meter's tile set its figure 5-11px higher than its neighbours').
 * 2. The phone's Dig chart is a chart, about 56 tall, not a row of dashes; the empty days stay 4px.
 * 3. The phone says "i stillingen" where the computer says "skridt tæller i stillingen", so a figure's
 *    words stay on one line in a third of the width. The hidden one is display:none, so a screen
 *    reader hears the words on screen and only those. */
.ministat dd {
    align-content: start;
    align-items: start;
}

.ministat dd > .stepsdash__unit--short {
    display: none;
}

@media (max-width: 47.9375rem) {
    .stepsdash .daybars__day--saved .daybars__slot {
        height: 50px;
    }

    /* The chart's height is won back in the card, so today's field still clears the tab bar at a
     * real 390x740 (the bar's top is at 658): Dig's rows closer, the meter tight under its words. */
    .stepsdash .stepsdash__you {
        row-gap: 4px;
    }

    .stepsdash .stepsdash__card.stepsdash__you {
        padding-block: 10px;
    }

    .ministat .ministat__meter {
        margin-top: 2px;
    }

    .ministat dd > .stepsdash__unit:has(+ .stepsdash__unit--short) {
        display: none;
    }

    /* One line at 390 by being short, not by nowrap: at 320 the English may wrap rather than spill
     * out of its tile (design review). */
    .ministat dd > .stepsdash__unit--short {
        display: block;
    }
}

/* === THE WEIGHT LADDER (audit 1006, D1; Kenneth's designer: "too many bold texts compete") ======
 * The roles are tokens (tokens.css, --weight-*), applied here at the specificity of the page rules
 * that set weights (measured in the browser: a weight inventory of 12 pages before and after).
 *   800  the H1 and the front hero only
 *   700  card titles, primary buttons, the one key figure per tile or row, a board's ranked value
 *        column, the own row
 *   600  table names, accordion questions, chip and tag labels, eyebrows and table heads (muted),
 *        the active nav item and segment, links that lead on
 *   500  field labels
 *   400  body, helper text, a table's secondary columns (muted), key/value values
 * My steps' own parts are b3's and are left as they are. */

/* 800: the page's title and the front hero. */
.pagehead .pagehead__title,
.adminshell .adminhead__title,
.front__title {
    font-weight: var(--weight-display);
}

/* 700: card titles. */
.front__h2,
.front__step-heading,
.door__heading,
.panel__title,
.panel .panel__title,
.helpgrid .panel__title--tiled,
.adcard__title,
.adminshell .admin__heading,
.adminshell .admin__legend,
.competitions-v4 .competition__name,
.lockblock__title,
.support__section-heading,
.standcard__label,
.standcard__name,
.teamcard__name,
.diplomacard__title {
    font-weight: var(--weight-strong);
}

/* 700: primary buttons; a secondary one 600. */
.button,
.button--main {
    font-weight: var(--weight-strong);
}

.button--secondary {
    font-weight: var(--weight-emphasis);
}

/* 700: the one key figure per tile or row, a board's ranked value, the own row and its disc. */
.figcard__value,
.figband__value,
.standcard__fig strong,
.deadline-panel__date,
.board-table td.board-table__figure--ranked,
.board-panel .board-table tbody .board-table__row--you > td,
.board-panel .board-table__row--you .board-table__pos,
.roster-panel .roster-table__row--you td,
.roster-table td.roster-table__figure:not(.roster-table__figure--quiet) {
    font-weight: var(--weight-strong);
}

/* 600: names in tables, accordion questions, chips and tags, eyebrows, the active nav item and
 * segment, links that lead on, the places that are not the own row's. */
.board-panel .board-table .board-table__name,
.roster-panel .roster-table__person,
.roster-table__mark,
.helpqa__q,
.statechip,
.competitions-v4 .teamrow--ready,
.competitions-v4 .teamrow--neutral,
.competitions-v4 .competition__state,
.front__photo .front__live,
.locked__chip,
.chip,
.board-table .board-table__you,
.roster-panel .roster-table__badge,
.emailcard__verified,
.board-table .board-table__pos,
.boardtabs__tab--on,
.bar__link[aria-current="page"],
.adminnav__link--on,
.adminsub__link--on,
a.link-standalone,
.attention__action,
.attention__what--strong,
.schedulecard__what,
.pagenav__step,
.competition__more-summary,
.pagehead--team .rename__summary,
.place-panel .place-change__summary,
.front__link,
.invite__link,
.emailcard .emailcard__value {
    font-weight: var(--weight-emphasis);
}

/* 500: field labels. */
.gate__label,
.field__label,
.door__label,
.gatecard .gate__label,
.gatecard--landing .gate__label,
.profileform .gate__label,
.placeform .gate__label,
.editform .field__label,
.adminshell .field__label,
.adminshell .field > label,
.profileform__language-label,
.details-panel .profileform__language-label {
    font-weight: var(--weight-label);
}

/* 400: a tile's label, key/value values, a table's secondary columns (muted), the tabs, pills and nav
 * items not chosen, a language choice not made. */
.figcard__label,
.figband__label,
.standcard__fig dt,
.door__note,
.locked__value,
.board-table td.board-table__figure:not(.board-table__figure--ranked),
.roster-table td.roster-table__figure--quiet,
.boardtabs__tab:not(.boardtabs__tab--on),
.bar__link:not([aria-current="page"]),
.adminnav__link:not(.adminnav__link--on),
.adminsub__link:not(.adminsub__link--on),
.langpick__label {
    font-weight: var(--weight-plain);
}

.board-table td.board-table__figure:not(.board-table__figure--ranked) {
    color: var(--colour-text-muted);
}

.board-panel .board-table tbody .board-table__row--you > td.board-table__figure {
    color: inherit;
}

.langpick__input:checked + .langpick__label {
    font-weight: var(--weight-emphasis);
}

/* Every table's head: the quiet spaced caps at 600 (the board's own rule above, in place). */
.roster-table thead th,
.support__table thead th,
.roster-panel .roster-table thead th,
.roster-panel .roster-table:not(.roster-table--invites) thead th,
.roster-panel .roster-table--invites th {
    color: var(--colour-text-muted);
    font-weight: var(--weight-emphasis);
}

/* The same roles at the specificity of the page rules that still won (measured). */
.appbar .bar__link[aria-current='page'],
.boardtabs .boardtabs__tab--on,
.adminshell .adminnav__link--on {
    font-weight: var(--weight-emphasis);
}

.appbar .bar__link:not([aria-current='page']),
.datepanel__list dd {
    font-weight: var(--weight-plain);
}

/* My team's own row is the own row throughout, as Standings' is (D1). */
.roster-panel .roster-table__row--you .roster-table__person,
.roster-panel .roster-table__row--you td.roster-table__figure--quiet {
    font-weight: var(--weight-strong);
}

/* The Admin link is a nav destination, not a button (D2 makes it a plain link). */
.appbar .bar__admin {
    font-weight: var(--weight-emphasis);
}

/* The deadline's sub-line supports its date; it does not compete with it. */
.teamwork .deadline-panel .deadline-panel__time {
    font-weight: var(--weight-plain);
}

/* === ONE STRONG THING PER SCREEN (audit 1006, D2; the advisor's 19:00) ===========================
 * Solid ink is the primary button and a board's own-row disc; nothing else is a filled ink shape.
 *   - The selected segment is a white chip on its tint track, ink at 600, a soft lift, and a 1px edge
 *     in the quiet ink: the edge is the indicator that meets 3:1 against the track (at least 5.5:1, WCAG
 *     1.4.11); white on the tint alone is about 1.1:1. Heights, the optical centring (#436) and the focus ring
 *     stay as they were.
 *   - The current nav item is a tint pill (the own-row tint) with ink at 600.
 *   - The notice's "i" is an outlined disc.
 *   - The Admin link is a plain nav link; the guest header's "Log ind" is a text link, and not on
 *     /sign-in itself. */
.boardtabs .boardtabs__tab--on,
.filters .filters__choice--on:not(.filters__choice--quiet),
.tabs__tab--current {
    background: var(--colour-surface);
    color: var(--colour-text);
    font-weight: var(--weight-emphasis);
    box-shadow: 0 0 0 1px var(--colour-text-muted), var(--shadow-sm);
}

.appbar .bar__link[aria-current='page'],
.appbar .bar__link[aria-current='page']:hover,
.appbar .bar__link[aria-current='page']:focus-visible {
    background: var(--colour-surface-own-row);
    color: var(--colour-text);
    font-weight: var(--weight-emphasis);
}

body:not(.adminshell) .status:not(.status--success)::before {
    border: 1.5px solid var(--colour-text);
    background: transparent;
    color: var(--colour-text);
    font-weight: var(--weight-strong);
}

body:not(.adminshell) .status.status--warning:not(.status--success)::before,
body:not(.adminshell) .status.status--error:not(.status--success)::before {
    border: 0;
    background: var(--colour-danger);
    color: var(--colour-text-inverse);
}

.appbar .bar__admin,
.appbar .topbar .bar__admin {
    border: 0;
    background: none;
    color: var(--colour-text-muted);
    font-size: 15px;
    font-weight: var(--weight-plain);
}

.gatebar--shared .gatebar__link--primary {
    min-height: 44px;
    padding: 0 8px;
    border: 0;
    background: none;
    color: var(--colour-text);
    font-weight: var(--weight-emphasis);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.gatebar--shared .gatebar__link--primary[aria-current='page'] {
    display: none;
}

/* FORCED COLOURS drop the chip's ground and edge, the whole of the selected state: a system outline says
 * it instead, as the admin's role choice already did. */
@media (forced-colors: active) {
    .boardtabs .boardtabs__tab--on,
    .filters .filters__choice--on:not(.filters__choice--quiet),
    .tabs__tab--current {
        outline: 2px solid Highlight;
    }
}

/* === ONE LANGUAGE SWITCHER, ONE FOOTER (audit 1006, D3 and D4) ====================================
 * D3: the language is the quiet text links "English · Dansk" wherever it is offered (the guest header,
 * the app footer); the current one at 600 and underlined, the other plain. The ink and outlined pills
 * and the EN/DA codes go. The control is unchanged underneath: a form whose choice is a submit button,
 * the current one marked aria-current, the group named by its (now visually hidden) label. My details
 * keeps its form field.
 * D4: every footer is one grid - the product's name on the left, novohealth on the right, and the
 * utilities (the language, "Log ud") in one quiet row under them. */
:is(.gatebar--shared, .sitefoot, .publicfoot) .language {
    display: flex;
    align-items: center;
    gap: 0;
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
}

:is(.gatebar--shared, .sitefoot, .publicfoot) .language .language__label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

:is(.gatebar--shared, .sitefoot, .publicfoot) .language .language__options {
    display: inline-flex;
    align-items: center;
    gap: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
}

:is(.gatebar--shared, .sitefoot, .publicfoot) .language .language__code {
    display: none;
}

:is(.gatebar--shared, .sitefoot, .publicfoot) .language .language__endonym {
    position: static;
    display: inline;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip: auto;
    clip-path: none;
    letter-spacing: normal;
    text-transform: none;
    white-space: nowrap;
}

/* The underline is the name's, so the separator before it stays plain. */
:is(.gatebar--shared, .sitefoot, .publicfoot) .language .language__current .language__endonym,
:is(.gatebar--shared, .sitefoot, .publicfoot) .language .language__choice:hover .language__endonym {
    text-decoration: underline;
    text-underline-offset: 3px;
}

:is(.gatebar--shared, .sitefoot, .publicfoot) .language :is(.language__current, .language__choice) {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
    padding: 0 4px;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
    color: var(--colour-text-muted);
    font-family: inherit;
    font-size: var(--font-size-sm);
    font-weight: var(--weight-plain);
    letter-spacing: normal;
    text-transform: none;
    line-height: 1;
    text-decoration: none;
}

:is(.gatebar--shared, .sitefoot, .publicfoot) .language .language__current {
    color: var(--colour-text);
    font-weight: var(--weight-emphasis);
}

/* === MY STEPS, KENNETH'S TARGET (design-v4-2026-10-01/my-steps-target-2026-10-05.webp; the advisor's
 * binding spec my-steps-target-spec-2026-10-05.md) ====================================================
 * The days and the converter (the top above them is THE TOP, at the end of this file). Green is entered
 * (the chart's bars, the meters, the saved day and the confirmation); Save stays ink (Kenneth's
 * decision 1). */

/* The days' heading on one line: "Dine 4 dage · 2.–5. oktober", the period regular. */
.days__title .days__range {
    color: var(--colour-text);
    font-weight: var(--font-weight-regular);
}

.days__legend .mark--unsaved {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--colour-primary) 55%, var(--colour-surface));
    vertical-align: middle;
}

.days__legend .mark--saved,
.days__legend .mark--missing {
    width: 10px;
    height: 10px;
    border: 0;
}

/* Today's card says when today counts, under its total. */
.dtile__counts {
    display: flex;
    gap: 6px;
    align-items: center;
    margin: 2px 0 0;
    color: var(--colour-text-muted);
    font-size: 13px;
}

.dtile__counts .lineicon {
    flex: 0 0 16px;
    width: 16px;
    height: 16px;
}

/* Save, with its check, and the green confirmation card beside it after a save. */
.days__save {
    gap: 12px;
}

.days__save-mark {
    display: inline-grid;
    flex: 0 0 28px;
    width: 28px;
    height: 28px;
    place-items: center;
    border: 2px solid currentColor;
    border-radius: 50%;
}

.days__save-mark .lineicon {
    width: 16px;
    height: 16px;
}

.days__actions .days__note--saved {
    display: flex;
    flex: 1 1 360px;
    gap: 14px;
    align-items: center;
    max-width: 680px;
    padding: 12px 18px;
    border: 1.5px solid var(--steps-saved-edge);
    border-radius: 14px;
    background: var(--steps-saved-ground);
    color: var(--colour-text);
    font-weight: var(--font-weight-regular);
}

.days__note--saved .days__note-mark {
    flex: 0 0 32px;
    width: 32px;
    height: 32px;
}

.days__note--saved .days__note-mark .lineicon {
    width: 18px;
    height: 18px;
}

.days__note-title {
    display: block;
    font-weight: var(--font-weight-bold);
}

.days__note .days__note-detail {
    display: block;
    color: var(--colour-text-muted);
    font-size: 14px;
    font-weight: var(--font-weight-regular);
}

/* The converter's copy button: the row's last control, 48 square, a field's edge. */
.button.converter__copy {
    display: inline-grid;
    flex: 0 0 48px;
    width: 48px;
    min-width: 48px;
    height: 48px;
    min-height: 48px;
    place-items: center;
    padding: 0;
    border: 1px solid var(--colour-border-field);
    border-radius: 10px;
    background: var(--colour-surface);
    color: var(--colour-text);
    cursor: pointer;
}

.button.converter__copy[hidden] {
    display: none;
}

.button.converter__copy:hover {
    background: var(--colour-surface-band);
}

.button.converter__copy:focus-visible {
    outline: 3px solid var(--colour-focus);
    outline-offset: 2px;
}

.converter__copy .lineicon {
    width: 22px;
    height: 22px;
}

@media (min-width: 80rem) {
    .steps-page .button.converter__copy {
        align-self: flex-end;
    }
}

/* A PHONE KEEPS ITS ORDER (spec: "Dig compact, today's card, then campaign and team"): the head's box
 * is flattened into the page's column so Kampagnen and Dit hold follow today's card. Du is compact:
 * the total and the two figures side by side, the chart under them. */
@media (max-width: 47.9375rem) {
    .days__actions .days__note--saved {
        flex-basis: 100%;
    }
}

/* The target's day cards: labels in the ladder's 500 in ink, the total's word with weight; the head
 * a little lower so Save stays above 800 at 1440 with today's "Tæller fra i morgen" line. */
.dtile__label,
.daycard__label {
    color: var(--colour-text);
    font-weight: var(--weight-label);
}

.dtile__total > span:first-child,
.daycard__total > span:first-child {
    font-weight: var(--font-weight-semibold);
}

/* The converter as compact as the target draws it: its line under the title, the row close under. */
.steps-page .converter .converter__hint,
.steps-page .converter > p:not([class]) {
    margin-bottom: 0;
}

@media (min-width: 80rem) {
    .steps-page .converter {
        gap: 10px;
    }
}

:is(.gatebar--shared, .sitefoot, .publicfoot) .language .language__choice:hover {
    color: var(--colour-text);
}

:is(.gatebar--shared, .sitefoot, .publicfoot) .language .language__options > * + *::before {
    margin-right: 8px;
    color: var(--colour-text-muted);
    font-weight: var(--weight-plain);
    content: "·" / "";
}

/* D4: one footer grid. */
.sitefoot .sitefoot__inner,
.sitefoot .sitefoot__inner--centred,
.publicfoot .publicfoot__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 4px 24px;
    text-align: left;
}

.sitefoot .sitefoot__inner > .page__footer-brand,
.publicfoot .publicfoot__inner > .publicfoot__brand {
    grid-row: 1;
    grid-column: 1;
    justify-self: start;
    margin: 0;
}

.sitefoot .sitefoot__inner > .page__operator,
.publicfoot .publicfoot__inner > .publicfoot__operator {
    grid-row: 1;
    grid-column: 2;
    justify-self: end;
    margin: 0;
}

.sitefoot .sitefoot__inner > .language,
.publicfoot .publicfoot__inner > .publicfoot__out {
    grid-row: 2;
    grid-column: 1 / -1;
    justify-self: start;
    margin: 0;
}

/* The utilities row is quiet: "Log ud" in the voice of a language not chosen (D4, the board), its 44px
 * target kept; and the row's text lines up with the product's name above it (its 4px of target padding
 * taken back by the row). */
.publicfoot .publicfoot__out .link-button {
    min-height: var(--touch-target-min);
    padding-inline: 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--weight-plain);
}

:is(.sitefoot, .publicfoot) .language .language__options {
    margin-inline-start: -4px;
}

/* The converter's title and its line close together, as the target draws them. */
.steps-page .converter .converter__title {
    margin-bottom: 0;
}

.steps-page .converter .converter__hint {
    margin-top: -4px;
}

/* The confirmation takes focus after a save (it is where the reader is told what happened); its ring
 * stays visible but in the confirmation's own green, not the heavy ink ring of a control. */
.days__note.days__note--saved:focus-visible,
.days__note.days__note--saved:focus {
    outline: 2px solid var(--steps-saved-edge);
    outline-offset: 3px;
}

/* === THE TARGET'S DESIGN REVIEW ==================================================================== */

/* An edited, unsaved day shows the legend's own mark: the blue dot "Ikke gemt endnu", where the pen
 * stood (the legend and the cards must match - the target's acceptance list). */
.is-unsaved .dtile__status::before,
.is-unsaved .daycard__status::before {
    content: "";
    display: inline-block;
    width: 10px;
    height: 10px;
    margin-right: 6px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--colour-primary) 55%, var(--colour-surface));
    vertical-align: -1px;
}

@media (min-width: 80rem) {
    .days__title {
        font-size: 26px;
    }
}

/* The focused confirmation keeps one border: the ring lies on the card's own edge. */
.days__note.days__note--saved:focus-visible,
.days__note.days__note--saved:focus {
    outline: 2px solid var(--steps-saved-edge);
    outline-offset: -1.5px;
}

/* === THE TARGET'S FIX ROUND (advisor 2026-10-07 02:45) ============================================
 * (1, Dig's figures below 1280, went with the head it measured: the top is THE TOP's below.) */

/* 2. "I alt" and its figure keep 8px between them; in a narrow card the figure goes under the word,
 * right-aligned. */
.dtile__total {
    flex-wrap: wrap;
    column-gap: 8px;
}

.dtile__total > b {
    margin-left: auto;
}

/* 3. The copy button stays beside the Omregnet field when the converter wraps (field and button one
 * group, from the left). */
@media (min-width: 48rem) and (max-width: 79.9375rem) {
    .steps-page .converter__answer {
        justify-content: flex-start;
        gap: 12px;
    }

    .steps-page .converter__answer > .converter__result {
        flex: 0 1 auto;
    }
}

/* 4. The confirmation is a status focused by the page (tabindex=-1), not a control: no focus ring,
 * one border, as the target draws it. role=status and the focus itself stay. */
.days__note.days__note--saved:focus,
.days__note.days__note--saved:focus-visible {
    outline: none;
}

/* === COMPETITIONS AFTER THE RESULT (audit 1006, D11) ================================================
 * The diploma is the page's one strong action, so the Viva Engage link on the ink band becomes the
 * on-ink outline (.button--onink-quiet's edge and ink) instead of the turquoise fill. Its arrow is
 * the shared SVG (D8), a gap from the words. */
.winnersband__open {
    gap: 8px;
}

.winnersband__open--quiet {
    border: var(--border-width-strong) solid var(--board-on-ink-muted);
    background: transparent;
    color: var(--colour-text-inverse);
}

.winnersband__open--quiet:focus-visible {
    outline-color: var(--colour-text-inverse);
}

/* The same hover as .button--onink-quiet, the on-ink outline it follows (design review). */
.winnersband__open--quiet:hover {
    background: var(--colour-rule-on-primary);
}

/* === THE DIPLOMAS SIDE BY SIDE (audit 1006, D11) ===================================================
 * The reader's own and the team's diploma as a pair from 64rem, the cards stretched to one height
 * with their buttons on one line (D5's card grid: the footer pinned); stacked below. */
.diplomas__pair {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
}

/* The grid's gap is the only space between them; the stacked cards' own sibling margin would set the
 * second one lower than the first. */
.diplomas__pair > .card {
    margin: 0;
}

@media (max-width: 47.9375rem) {
    .diplomas__pair {
        gap: 16px;
    }
}

@media (min-width: 64rem) {
    .diplomas__pair {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        align-items: stretch;
    }

    .diplomas__pair > .card {
        display: flex;
        flex-direction: column;
    }

    .diplomas__pair > .card > .diplomas__actions {
        margin-top: auto;
        padding-top: var(--space-md);
    }
}

/* === ALIGNMENT PRIMITIVES (audit 1006, D5) ===================================================== */

/* 1. Stat and fact tiles: label, figure and small line are rows read from the top, so the rows line
 * up across the tiles; a row whose tiles differ keeps every tile's small line (the partials). */
.figcard,
.figband__figure {
    align-items: start;
}

/* In the stat row the three lines are the row's own tracks, not each tile's: a label that wraps (the
 * admin overview's "Total til og med i går" at 390) moves the figures of its whole row down with it,
 * so they stay on one line. Each card takes three rows of the row and passes them on to its words;
 * the tile spans them, at the top. The cards keep their own padding and the row its gap. */
@supports (grid-template-rows: subgrid) {
    .figrow__item {
        grid-row: span 3;
        display: grid;
        grid-template-rows: subgrid;
        row-gap: 0;
    }

    .figcard {
        grid-row: 1 / -1;
        display: grid;
        grid-template-columns: auto minmax(0, 1fr);
        grid-template-rows: subgrid;
        row-gap: 0;
    }

    .figcard__tile {
        grid-row: 1 / -1;
        grid-column: 1;
        align-self: start;
    }

    .figcard__words {
        grid-row: 1 / -1;
        grid-column: 2;
        grid-template-rows: subgrid;
        row-gap: 0;
    }
}

@media (min-width: 62.5rem) {
    .figband--team .figband__figures {
        align-items: start;
    }
}

/* 2. Card grids: the cards stretch to the row, and a card's foot - the announcement, the disclosure,
 * the team's standing, whichever follow the fact tiles - sits at its bottom, so the last lines of two
 * cards side by side are on one line. Every part has its own row: the head; the state when a narrow
 * card puts it under the heading (empty otherwise); the rule; the tiles; then up to three foot parts,
 * the first of which takes the free height and sits at its end, the others following it. The rows are
 * fixed, not counted, because the card cannot query its own width. */
.competitions-v4 .competition {
    grid-template-rows: auto auto auto auto 1fr auto auto;
}

.competitions-v4 .competition__body > .competition__rule {
    grid-row: 3;
}

.competitions-v4 .competition__body > .competition__facts {
    grid-row: 4;
}

.competitions-v4 .competition__body > .competition__facts + * {
    grid-row: 5;
    align-self: end;
}

.competitions-v4 .competition__body > .competition__facts + * + * {
    grid-row: 6;
}

.competitions-v4 .competition__body > .competition__facts + * + * + * {
    grid-row: 7;
}

/* 3. Control heights, one token per context: a header pill the touch target (44), a form control and
 * its button --control-height (48), the admin from 48rem --admin-control (40, admin.css). The front
 * page's twin doors are in their own rule (.door .door__go). */

/* The app bar's links were 45.25 (11 + a 23.25 line + 11): at line-height 1 the link is the target's
 * 44, and its label comes down by the nudge (a fixed-height centre moves a label half its top padding). */
.appbar .bar__link {
    line-height: 1;
    padding-block: calc(var(--optical-nudge) * 2) 0;
}

/* 4. Pills and discs: the label on the capitals' centre. Measured (Chrome 131 and 154, the Novo
 * face): "Kører nu" 1.34 high, the roster initials 1.30, "Bekræftet" 1.07, "Låst" and the admin chips
 * 0.70. The face's declared cap height is not its drawn one, so `text-box: trim-both cap alphabetic`
 * left "Kører nu" 0.48 high where the nudge leaves it 0.23; the nudge is the method throughout.
 * A chip keeps its height: its own padding, moved by the nudge. */
.competitions-v4 .competition__state {
    padding-top: calc(var(--chip-padding-block) + var(--optical-nudge));
    padding-bottom: calc(var(--chip-padding-block) - var(--optical-nudge));
}

.emailcard__verified {
    padding-top: calc(4px + var(--optical-nudge));
    padding-bottom: calc(4px - var(--optical-nudge));
}

/* A disc of fixed size centres its label, so the top padding is twice the move. */
.roster-table__mark,
.whoami__initials,
.appbar .whoami__initials {
    padding-top: calc(var(--optical-nudge) * 2);
}

/* === TEXT WRAP (audit 1006, D6) ================================================================ */

/* Running text breaks its lines evenly and leaves no word alone on the last one; headings and card
 * titles balance their lines. The style only (text-wrap-style), so no element's own white-space or
 * nowrap is touched; it is inherited, and the headings and titles take theirs. */
body {
    text-wrap-style: pretty;
}

h1,
h2,
h3,
.status__title,
.panel__title,
.competition__name,
.competitions__name,
.teamcard__name,
.teamfind__name,
.diploma__name,
.board-empty__title,
.adminhead__title {
    text-wrap-style: balance;
}

/* === THE PLACEMENT, READ-ONLY AFTER THE RESULT (advisor 2026-10-07 02:45) ===========================
 * Once the result is published the card states the team's country and EVP area as two rows, the label
 * muted on the left and the value on the right at 400 (D1: key/value values); no control. */
.place-facts {
    margin: 0;
}

.place-facts__row {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 4px 16px;
    padding: 10px 0;
}

.place-facts__row + .place-facts__row {
    border-top: var(--border-width) solid var(--colour-rule-warm);
}

.place-facts__row dt {
    color: var(--colour-text-muted);
}

.place-facts__row dd {
    margin: 0;
    font-weight: var(--font-weight-regular);
}

/* === ONE FIELD ERROR (audit 1006, D7) ========================================================== */

/* Every field error is one component: under the label, above its field, the message in ink 14/500 led
 * by a 16px Lava Red disc with a white "!" - the disc says it is an error, never red text. The field
 * has a 2px red edge; focused, one 3px band in the focus ink lies over that edge, so there is one line
 * and the focus is plainly seen (D7 as amended by the advisor, 2026-10-07 06:00: a red band over the
 * red edge changed by one pixel and hid where the focus was). My steps (the day grid and the converter) keeps its own until its owner
 * takes this: the page is b3's, so every rule here stops at .steps-page.
 *
 * THE :is() GROUPS ARE SPECIFICITY FLOORS, not contexts: `:root` matches every page, and the other
 * argument is the most specific earlier rule each declaration has to win over (the sign-in sheet's
 * field error, the details panel's invalid field, the admin's focused primary field). */
:is(.gateshell.gateshell--sheet .gatecard .gate__form, :root) .field__error:not(.steps-page *, .converter *) {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    color: var(--colour-text);
    font-size: 0.875rem;
    font-weight: var(--weight-label);
    line-height: 1.25rem;
}

:is(.gateshell.gateshell--sheet .gatecard .gate__form, :root) .field__error:not(.steps-page *, .converter *)::before {
    display: grid;
    flex: 0 0 16px;
    place-items: center;
    width: 16px;
    height: 16px;
    /* On the first line's centre: the message's 20px line (1.25rem above), not the disc's own. */
    margin-top: calc((1.25rem - 16px) / 2);
    border-radius: 50%;
    background: var(--colour-danger);
    color: var(--colour-text-inverse);
    font-size: 11px;
    font-weight: var(--weight-display);
    line-height: 1;
    content: "!" / "";
}

@media (forced-colors: active) {
    :is(.gateshell.gateshell--sheet .gatecard .gate__form, :root) .field__error:not(.steps-page *, .converter *)::before {
        border: 1px solid CanvasText;
        background: Canvas;
        color: CanvasText;
    }
}

:is(.details-panel .field, :root) :is(input, select, textarea)[aria-invalid='true']:not(.steps-page *, .converter *) {
    border: var(--border-width-strong) solid var(--colour-danger);
}

:is(.adminshell .field--primary, :root) :is(input, select, textarea)[aria-invalid='true']:not(.steps-page *, .converter *):focus-visible {
    outline: var(--focus-ring-width) solid var(--colour-focus);
    outline-offset: calc(-1 * var(--focus-ring-width));
    border-color: var(--colour-danger);
    box-shadow: none;
}

/* === ONE CONFIRM CARD (audit 1006, D7) ========================================================= */

/* Every confirmation, and the error pages, is one card: at most 480 wide, 32 inside (24 on a phone) with
 * the same space above and below, an optional 48 tile, a balanced 24/700 title, the body 16 muted with
 * 12 under the title and between paragraphs, and its actions stacked at full width, the primary first.
 * The card sits 96 under the bar on a computer and 32 on a phone. It carries its own surface (the card's
 * ground, rule, radius and one shadow) and its tile's, so a new confirmation needs only .confirm-card and
 * its parts; the team's confirmations (.decision) and the error pages (.message) carry them beside their
 * own classes.
 *
 * Anchored on the card's parent (`main` or the error page's `.errormain`) so these win over the older
 * .decision and .message rules they replace, which are as specific and come earlier. */

/* The 96 (32) is the whole gap under the bar: the page wrapper gives up its own top padding (24, 36 on a
 * phone), and the error pages stop centring the card in the window's height. */
.page:has(> main > .confirm-card) {
    align-items: flex-start;
    padding-top: 0;
}

:is(.errormain, main):has(> .confirm-card) {
    padding-top: var(--space-3xl);
}

:is(.errormain, main) > .confirm-card {
    box-sizing: border-box;
    width: 100%;
    max-width: 480px;
    margin-inline: auto;
    padding: var(--space-lg);
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: var(--radius-2xl);
    background: var(--colour-surface);
    box-shadow: var(--shadow-md);
}

:is(.errormain, main) > .confirm-card > :is(.confirm-card__tile, .gatecard__icon) {
    display: grid;
    place-items: center;
    width: 48px;
    height: 48px;
    margin: 0 0 var(--space-sm);
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-primary);
}

/* The team cards' title sits in a header whose own bottom margin (32) would stand between it and the body. */
:is(.errormain, main) > .confirm-card > .decision__header {
    margin: 0;
}

:is(.errormain, main) > .confirm-card .confirm-card__title {
    margin: 0;
    font-size: 1.5rem;
    font-weight: var(--weight-strong);
    line-height: 1.25;
    text-wrap-style: balance;
}

:is(.errormain, main) > .confirm-card .confirm-card__body {
    margin: var(--space-xs) 0 0;
    color: var(--colour-text-muted);
    font-size: 1rem;
}

:is(.errormain, main) > .confirm-card .confirm-card__actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    margin: var(--space-md) 0 0;
}

:is(.errormain, main) > .confirm-card .confirm-card__actions :is(form, .button) {
    width: 100%;
    margin: 0;
}

@media (max-width: 47.9375rem) {
    :is(.errormain, main):has(> .confirm-card) {
        padding-top: var(--space-lg);
    }

    /* Only the error page's main is a column that centred the card in its height; the team pages' main
     * is a grid, where this would stop the card's column stretching and put it at the left. */
    .errormain:has(> .confirm-card) {
        justify-content: flex-start;
    }

    :is(.errormain, main) > .confirm-card {
        padding: var(--space-md);
    }
}

/* === ONE STATUS (audit 1006, D7) =============================================================== */

/* A status that answers a press sits under the button that made it (My details' saved band under Save),
 * 16 below it. The status itself is the band above ("plain .status takes the neutral mark"). */
.button + .status {
    margin-top: var(--space-sm);
}

/* The reload after My details' save lands on its band (#profile-saved) with Save still in view above it:
 * the 8rem holds Save (48), its 16 to the band, and air above Save (the bar does not stick, so it
 * takes none). Measured: at 390x740 Save at 61, the band at 125; at 1440x800 both in the window. */
#profile-saved {
    scroll-margin-top: 8rem;
}

/* === THE PRIVACY NOTICE (advisor 2026-10-07 00:05) =================================================
 * The footers' utilities row (D4) is one flex row now: the privacy link first, then the language or the
 * sign-out. The link speaks in the language choices' quiet voice, its 44px target kept and its text
 * lined up with the product's name above it. */
.sitefoot .sitefoot__inner > .footutils,
.publicfoot .publicfoot__inner > .footutils {
    display: flex;
    flex-wrap: wrap;
    grid-row: 2;
    grid-column: 1 / -1;
    align-items: center;
    justify-self: start;
    gap: 0 24px;
    margin: 0;
}

.footutils .footutils__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-target-min);
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--weight-plain);
    line-height: 1;
    text-decoration: none;
}

.footutils .footutils__link:hover {
    color: var(--colour-text);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* The error pages' footer is a flex row from 64rem (.errorshell), not the D4 grid: the utilities row
 * takes a line of its own there too. */
@media (min-width: 64rem) {
    .errorshell .sitefoot .sitefoot__inner {
        flex-wrap: wrap;
        row-gap: 4px;
    }

    .errorshell .sitefoot .sitefoot__inner > .footutils {
        flex-basis: 100%;
    }
}

/* On the sign-in card and the welcome step: one quiet line under the action, underlined, because it is
 * a link standing alone under a form. */
.gatecard__privacy {
    margin: var(--space-md) 0 0;
    color: var(--colour-text-muted);
    font-size: var(--font-size-sm);
}

.gatecard__privacy a {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.gatecard__privacy a:hover {
    color: var(--colour-text);
}

/* The notice itself: one gate card at a reading width (about 70 characters a line; the gate's 400px
 * card is for one field), sections under hairlines. A phone keeps the gate's full-width card. */
@media (min-width: 48rem) {
    .gateshell .gatecard.gatecard--doc {
        max-width: 640px;
    }
}

.privacy__section {
    margin-top: 24px;
    padding-top: 24px;
    border-top: var(--border-width) solid var(--colour-rule-warm);
}

.privacy__section h2 {
    margin: 0 0 8px;
    color: var(--colour-text);
    font-size: var(--font-size-lg);
    font-weight: var(--weight-strong);
}

.privacy__section p,
.privacy__list,
.privacy__roles {
    margin: 0;
    color: var(--colour-text);
    font-size: var(--font-size-base);
    line-height: 1.55;
}

.privacy__section p + p,
.privacy__section .privacy__roles + p {
    margin-top: 12px;
}

.privacy__list {
    padding-left: 20px;
}

.privacy__list li + li {
    margin-top: 4px;
}

.privacy__role + .privacy__role {
    margin-top: 12px;
}

.privacy__role dt {
    font-weight: var(--weight-emphasis);
}

.privacy__role dd {
    margin: 2px 0 0;
    line-height: 1.55;
}

.privacy__section a {
    color: var(--colour-accent-on-surface);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* === THE NO-TEAM STATE (audit 1006, D7) ======================================================== */

/* The sheet's empty state (item 8) as its own card: the 56 Ice Blue tile, the sentence 18/700 as the
 * heading, a muted line under it, and the one action with the quiet link to the other at the same text
 * size (16), centred. On a phone the button fills the line (every phone primary does) and the link sits
 * under it; this is the reference for every no-team state. Once per page (the page decides where). */
.noteamstate {
    display: grid;
    justify-items: center;
    gap: var(--space-2xs, 8px);
    padding: var(--space-lg) var(--space-sm);
    border: var(--border-width) solid var(--colour-rule-warm);
    border-radius: var(--radius-2xl);
    background: var(--colour-surface);
    text-align: center;
}

.noteamstate__tile {
    display: grid;
    place-items: center;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--colour-surface-tile);
    color: var(--colour-primary);
}

.noteamstate__tile .lineicon {
    width: 26px;
    height: 26px;
}

.noteamstate__title {
    margin: 0;
    font-size: 1.125rem;
    font-weight: var(--weight-strong);
    line-height: 1.3;
    text-wrap-style: balance;
}

.noteamstate__lede {
    margin: 0;
    color: var(--colour-text-muted);
}

.noteamstate__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs) var(--space-md);
    margin: var(--space-2xs, 8px) 0 0;
}

/* The quiet link is the project's (.quietlink, its arrow and 44 target), at the button's text size. */
.noteamstate__create {
    font-size: 1rem;
}

/* === ONE GATE CARD (audit 1006, D7) ============================================================ */

/* Every gate card's head is partials/gate-head; /sign-in's card, outside the sheet shell, is a second
 * selector on the sheet's own head rules (.gateshell--sheet .gatecard__head, above), so the two cannot
 * drift. */

/* The field reads label, hint, error, field, 6 apart, as the sheet's do: /sign-in's hint was the line
 * under its entry row (12 above it); under the label it takes the sheet's spacing. */
.gatecard--signin .gate__form .gate__label + .gate__hint {
    margin: 0 0 6px;
}

/* === THE TEAM'S CONFIRMATIONS (audit 1006, 201-206) ================================================
 * 201: each member on the hand-over is a list button - 56 tall, the name on the left and a chevron on
 * the right - so the names read as the choices; the way out under them is the quiet button. */
.handover .handover__choice {
    justify-content: space-between;
    gap: 12px;
    min-height: 56px;
    padding: 0 16px;
}

.handover .handover__choice svg {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
}

/* === THE PARTICIPANT PAGES' CONTENT POLISH (audit 1006, b3's fix/page-content-polish) =================
 * Item 17: the front page has one content column for header, body and footer - the logo at the body's
 * edge (x 141 at 1440), not 45px left of it. */
@media (min-width: 64rem) {
    .gateshell--front .gatebar__inner,
    .gateshell--front .publicfoot__inner {
        box-sizing: border-box;
        max-width: 1240px;
        margin-inline: auto;
        padding-inline: 48px;
    }
}

/* The doors' description now stands at the card's own padding, under the head, as the label and the
 * field do (it was indented under the title). */
.door > .door__line {
    margin: 0;
}

/* The materials button now stands under the text it belongs to (item 17), not in the tiles' column:
 * the grid placement and the pull-up it had there go. */
.front__materials-inner .front__materials-open {
    grid-column: auto;
    margin: 20px 0 0;
}

/* Item 16: on a phone a date row is always its label over its value (Support's and Materials'
 * rows broke at different points); item 24: the security sentence closes the contact card. */
@media (max-width: 47.9375rem) {
    .helpgrid .datepanel__row {
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
    }

    .helpgrid .datepanel__row dt {
        flex: none;
    }
}

.helpcontact .helpcontact__never {
    margin-top: 16px;
}

/* Item 19, My team: the join link reads at the body's 500 and breaks anywhere; the own row's initials
 * keep a white disc on the row's tint; "Fjern" is a quiet underlined button at the body's size. */
.invite__linkbox .invite__link {
    font-weight: var(--font-weight-medium);
    word-break: break-all;
}

.roster-table__row--you .roster-table__mark {
    background: var(--colour-surface);
}

.roster-table .roster-table__action--text {
    color: var(--colour-text);
    font-size: 14px;
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* My team's left column: the roster with the deadline and the placement under it (item 19). It is the
 * roster's place in the side-by-side grid, across all rows; on a phone it stacks as the column did. */
.teamwork__col {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    min-width: 0;
}

@media (min-width: 64rem) {
    .teamwork--beside > .teamwork__main > .teamwork__col {
        grid-column: 1;
        grid-row: 1 / -1;
        margin: 0;
    }

    .teamwork--beside .teamwork__col > .roster-panel {
        margin: 0;
    }
}

/* Item 20: the diploma not ready yet is the sheet's empty state, its quiet link under the line. */
.diploma-empty .diploma-empty__link {
    margin: 8px 0 0;
}

/* Item 23: one label size on Create (the placement's "Land" and "EVP-område" were 13 beside the
 * team name's 14), and one cross-link pattern on Create and Find - the question and its link at the
 * same 15px, the link semibold. */
.placegroup .gate__label {
    font-size: 14px;
}

.gatecard .gate__alternate {
    font-size: 15px;
}

.gatecard .gate__alternate .quietlink {
    font-size: inherit;
}

/* === ONE ARROW (audit 1006, D8) ================================================================ */

/* The arrow is drawn, never the "→" glyph: a button's is partials/button-arrow (18), a quiet link's and a
 * card note's the line icon's arrow-right. A button spaces its arrow by one gap, 8 from the words, the
 * same in every button: the partial's own 10px margin stood beside the gap some buttons already had (18
 * on Competitions' winners band) and stood alone in the others (10). */
.button:has(> .button__arrow) {
    gap: 8px;
}

.button > .button__arrow,
.winnersband__open > .button__arrow {
    margin-left: 0;
}

/* A link card's note ends in the arrow at the note's size (13, 12 on a phone), 6 from its words as a quiet
 * link's. */
.figcard__note .lineicon {
    width: 1em;
    height: 1em;
    margin-left: 6px;
    vertical-align: -0.125em;
}

/* The team-change confirmations' arrow between the team left and the team joined (switch, create
 * instead): drawn, at the size the glyph had, and still only where the two sides sit side by side. */
.move__arrow .lineicon {
    display: block;
    width: 20px;
    height: 20px;
}

/* Competitions' "Invitér … mere" is the project's quiet link, its arrow and 44 target, at the band's own
 * text: the row's 16 and bold, as the link was before it took the arrow. */
.teamrow .quietlink {
    font-size: inherit;
    font-weight: var(--font-weight-bold);
}

/* === THE TOP, KENNETH'S LOCKED TARGET (steps-top-comparison-target-2026-10-05.png) ==================
 * My steps and Standings share it. Three tinted cards, each a heading with one icon over ONE white
 * panel; the figures in a panel are split by hairlines, never boxed. Own figures 700, the field's 400
 * and muted. Green is entered: the saved days' bars and the meters. */
.stattop {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
    margin: 0;
}

.stattop__card {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
    padding: 16px;
    border: 1px solid var(--colour-rule-on-tint);
    border-radius: 16px;
    background: var(--colour-surface-band);
}

.stattop__head {
    display: flex;
    gap: 12px;
    align-items: center;
    min-width: 0;
    min-height: 40px;
}

.stattop__icon {
    display: inline-grid;
    flex: 0 0 36px;
    width: 36px;
    height: 36px;
    place-items: center;
    border-radius: 50%;
    background: var(--colour-surface-tile);
}

.stattop__icon .lineicon {
    width: 18px;
    height: 18px;
}

.stattop__heading {
    min-width: 0;
}

.stattop__title {
    margin: 0;
    color: var(--colour-text);
    font-size: 18px;
    font-weight: var(--font-weight-bold);
    line-height: 1.2;
}

/* The name line: one line, cut with an ellipsis at the card's width; the whole name is the title. */
.stattop__name {
    overflow: hidden;
    margin: 2px 0 0;
    color: var(--colour-text-muted);
    font-size: 14px;
    line-height: 1.3;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.stattop__panel {
    flex: 1 1 auto;
    min-width: 0;
    padding: 16px;
    border-radius: 12px;
    background: var(--colour-surface);
}

.stattop dl,
.stattop dd,
.stattop__now,
.stattop__when,
.stattop__empty,
.stattop__links,
.stattop__ends,
.stattop__caption {
    margin: 0;
}

.stattop__value {
    display: block;
    color: var(--colour-text);
    font-size: 22px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    line-height: 1.15;
    white-space: nowrap;
}

.stattop__fig--theirs .stattop__value {
    color: var(--colour-text-muted);
    font-weight: var(--font-weight-regular);
}

.stattop__label,
.stattop__note {
    display: block;
    color: var(--colour-text-muted);
    font-size: 14px;
    line-height: 1.3;
}

/* Every figure's label on one line (Kenneth's GO, 14:50). */
.stattop__label {
    white-space: nowrap;
}

.stattop__note {
    margin-top: 4px;
    font-size: 13px;
}

.stattop__meter.meter {
    display: block;
    width: 100%;
    max-width: 100%;
    height: 8px;
    margin: 8px 0 0;
    border-radius: 999px;
    background: color-mix(in srgb, var(--colour-border-field) 25%, var(--colour-surface));
}

.stattop__meter .meter__fill {
    border-radius: 999px;
    background: var(--colour-success);
}

/* Dig: the chart, a hairline, the 2x2. */
.stattop__panel--you {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}

.stattop__chart {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    margin: 0;
}

.stattop__bars {
    display: grid;
    grid-auto-columns: minmax(0, 1fr);
    grid-auto-flow: column;
    gap: 4px;
    align-items: end;
    margin: 0;
    padding: 0;
    list-style: none;
}

.stattop__day {
    display: flex;
    flex-direction: column;
    gap: 4px;
    align-items: center;
    min-width: 0;
}

.stattop__slot {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    width: 100%;
    height: 96px;
}

.stattop .stattop__bar {
    position: static;
    display: block;
    width: min(100%, 22px);
    border-radius: 3px 3px 0 0;
    background: var(--colour-success);
}

/* A day not entered yet is a pale bar; a day that ended without steps a low stub on the baseline. */
.stattop .stattop__day--future .stattop__bar,
.stattop .stattop__day--today .stattop__bar {
    height: 22%;
    background: color-mix(in srgb, var(--colour-border-field) 30%, var(--colour-surface));
}

.stattop .stattop__day--missing .stattop__bar {
    height: 6%;
    background: var(--colour-border-field);
}

.stattop__num {
    color: var(--colour-text-muted);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    line-height: 14px;
}

.stattop__ends {
    display: flex;
    justify-content: space-between;
    color: var(--colour-text-muted);
    font-size: 11px;
    line-height: 14px;
}

.stattop__caption {
    margin-top: 4px;
    color: var(--colour-text-muted);
    font-size: 13px;
}

.stattop__figs {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.stattop__fig {
    min-width: 0;
    padding: 0 0 0 16px;
}

.stattop__figs > .stattop__fig--wide + .stattop__fig {
    padding-left: 0;
    padding-right: 16px;
}

.stattop__figs > .stattop__fig + .stattop__fig + .stattop__fig {
    border-left: 1px solid var(--colour-rule-on-tint);
}

.stattop__figs > .stattop__fig:not(.stattop__fig--wide) {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--colour-rule-on-tint);
}

.stattop__figs > .stattop__fig--wide {
    grid-column: 1 / -1;
    padding: 0;
}

.stattop__inline {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
    align-items: baseline;
}

.stattop__inline .stattop__value,
.stattop__inline .stattop__label {
    display: inline;
}

/* Kampagnedag: the day large and centred, the bar, the period. */
.stattop__panel--campaign {
    display: flex;
    flex-direction: column;
    gap: 10px;
    justify-content: center;
    text-align: center;
}

.stattop__daybig {
    display: block;
    color: var(--colour-text);
    font-size: 40px;
    font-weight: var(--weight-strong);
    font-variant-numeric: tabular-nums;
    line-height: 1.05;
    white-space: nowrap;
}

/* The no-team sentence is a sentence, not a figure's label: it wraps. */
.stattop__label.stattop__label--wrap {
    white-space: normal;
}

.stattop__state {
    margin: 0;
    color: var(--colour-text-muted);
    font-size: 13px;
}

.stattop__when {
    color: var(--colour-text-muted);
    font-size: 14px;
}

.stattop__empty {
    color: var(--colour-text);
    font-weight: var(--font-weight-bold);
}

.stattop__links {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;
    align-items: center;
    margin-top: 8px;
}

/* From 768 the chart and the 2x2 sit side by side, a hairline between them. */
@media (min-width: 48rem) {
    .stattop__panel--you {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        gap: 0;
    }

    .stattop__chart {
        padding-right: 16px;
        border-right: 1px solid var(--colour-rule-on-tint);
    }

    /* Row for row as Dit hold (the advisor's 08:00): the figures start where the team's start, not
     * centred beside the chart, so their baselines line up across the row. */
    .stattop__panel--you > .stattop__figs {
        align-content: start;
        padding-left: 16px;
    }
}

/* One row from 1024: Dig the widest, Kampagnedag the narrowest, as the target. */
@media (min-width: 64rem) {
    .stattop {
        grid-template-columns: minmax(0, 2.1fr) minmax(0, 0.85fr) minmax(0, 1.25fr);
    }

    .stattop__panel--you {
        grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    }

    .stattop__name {
        white-space: nowrap;
    }
}

/* Between 1024 and 1280 the panels and figures step down a size so every label keeps its line. */
@media (min-width: 64rem) and (max-width: 79.9375rem) {
    .stattop__card {
        padding: 12px;
    }

    .stattop__panel {
        padding: 12px;
    }

    .stattop__value {
        font-size: 19px;
    }

    .stattop__daybig {
        font-size: 32px;
    }

    .stattop__label {
        font-size: 12px;
    }

    .stattop__fig {
        padding-left: 10px;
    }

    .stattop__figs > .stattop__fig--wide + .stattop__fig {
        padding-right: 10px;
    }

    .stattop__slot {
        height: 72px;
    }

    .stattop__num {
        font-size: 10px;
    }
}

/* Below 1440 every label keeps its one line (Kenneth's GO, 14:50; measured at 1024, 1280 and 1366 on
 * both pages): Dig takes more of the row and its 2x2 more of Dig, Kampagnedag gives way, and the
 * figures step down a size. */
@media (min-width: 64rem) and (max-width: 89.9375rem) {
    .stattop {
        grid-template-columns: minmax(0, 2.15fr) minmax(0, 0.82fr) minmax(0, 1.28fr);
    }

    .stattop__head {
        gap: 8px;
    }

    .stattop__title {
        font-size: 16px;
    }

    .stattop__panel--you {
        grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    }

    .stattop__fig {
        padding-left: 10px;
    }

    .stattop__figs > .stattop__fig--wide + .stattop__fig {
        padding-right: 10px;
    }

    .stattop__value {
        font-size: 19px;
    }

    .stattop__label {
        font-size: 12px;
    }

    .stattop__chart {
        padding-right: 12px;
    }

    .stattop__panel--you > .stattop__figs {
        padding-left: 12px;
    }

    .stattop__daybig {
        font-size: 32px;
    }

    .stattop__panel--campaign {
        padding-inline: 8px;
    }
}

/* From 1024 to 1280 three cards in one row do not fit (Kampagnedag's heading ran into Dit hold at
 * 1024): Dig takes the whole first row, Kampagnedag and Dit hold share the second. */
@media (min-width: 64rem) and (max-width: 79.9375rem) {
    .stattop {
        grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    }

    .stattop__card--you {
        grid-column: 1 / -1;
    }

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

/* More than ten bars beside the 2x2 run their numbers together (measured at 1024, 1280 and 1440, 14
 * days): every other day keeps its number, and the first and last date under them say the range. */
@media (min-width: 48rem) {
    .stattop__bars:has(> :nth-child(11)) .stattop__day:nth-child(even) .stattop__num {
        visibility: hidden;
    }
}

/* On a phone the cards stack. ON MY STEPS DIG STAYS FIRST, and Kampagnedag and Dit hold come after
 * today's day card, before the converter (the advisor's 2026-10-08 08:00), so entry stays high. */
@media (max-width: 47.9375rem) {
    .steps-page .pagestack > .stattop {
        display: contents;
    }

    .steps-page .pagestack > .stattop > .stattop__card--campaign,
    .steps-page .pagestack > .stattop > .stattop__card--team {
        order: 1;
    }

    /* DIG ABOVE TODAY'S CARD, AND TODAY'S FIELD STILL ABOVE THE TAB BAR (the advisor's 2026-10-08 08:00):
     * on My steps the day strip right under Dig already says every day's state, so Dig drops its chart
     * here and its rows sit closer. Measured at a real 390x740: with the chart, today's first field
     * sat at 745-793 under the tab bar at 658. */
    .steps-page .stattop__card--you .stattop__chart {
        display: none;
    }

    .steps-page .stattop__card--you {
        gap: 6px;
        padding: 8px 12px;
    }

    .steps-page .stattop__card--you .stattop__figs > .stattop__fig:not(.stattop__fig--wide) {
        margin-top: 8px;
        padding-top: 8px;
    }

    .steps-page .stattop__card--you .stattop__head {
        min-height: 0;
    }

    .steps-page .stattop__card--you .stattop__icon {
        flex-basis: 30px;
        width: 30px;
        height: 30px;
    }

    .steps-page .stattop__card--you .stattop__title {
        font-size: 16px;
    }

    .steps-page .stattop__card--you .stattop__panel {
        padding: 8px 12px;
    }

    .steps-page .stattop__card--you .stattop__meter.meter {
        margin-top: 6px;
    }

    .steps-page .stattop__card--you .stattop__note {
        margin-top: 2px;
    }

    .stattop__card {
        gap: 10px;
        padding: 12px;
    }

    .stattop__panel {
        padding: 12px;
    }

    .stattop__panel--you {
        gap: 12px;
    }

    .stattop__slot {
        height: 48px;
    }

    .stattop__value {
        font-size: 18px;
    }

    .stattop__label {
        font-size: 12px;
    }

    .stattop__daybig {
        font-size: 30px;
    }

    .stattop__num {
        font-size: 10px;
    }

    .stattop__caption {
        display: none;
    }
}

/* === PARTICIPANT QA (2026-10-07) =====================================================================
 * My team's invitation row below 30rem: the state pill and the two actions do not fit side by side
 * (the pill ran 23px under "Send a reminder" at 390, in both languages), so the actions take a line of
 * their own under the pill. From 30rem the board's two-by-two holds. */
@media (max-width: 29.999rem) {
    .roster-panel .roster-table--invites td.roster-table__action-cell {
        grid-column: 1 / -1;
        grid-row: 3;
        justify-self: start;
    }
}

/* THE CHART'S TOOLTIP (Kenneth 6/10; public/js/day-chart.js): small and dark above the bar under the
 * pointer, the day and its figure. Absolutely placed in the chart, so nothing moves under it; it can be
 * pointed at (WCAG 1.4.13, hoverable) and Escape dismisses it. */
.stattop__chart {
    position: relative;
}

.stattop__tip {
    position: absolute;
    z-index: 2;
    padding: 4px 8px;
    border-radius: 6px;
    background: var(--colour-text);
    color: var(--colour-surface);
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    line-height: 1.3;
    white-space: nowrap;
    transform: translate(-50%, calc(-100% - 6px));
}

.stattop__tip[hidden] {
    display: none;
}
