/* ══════════════════════════════════════════════════════════════════════════
   THE COMPOSER — the wizard as a conversation that writes a document

   Three parts, one argument: a rail at the top that says where you are, a
   sheet of paper in the middle that IS the product, and a floating tray at
   the bottom that holds one question at a time.

   ONE DESIGN AT EVERY VIEWPORT, AND CSS OWNS THE HEIGHT. The tray is
   `height: auto` under two static caps (plain / roomy) and the controller
   only folds it — see the header of wizard_composer_controller.js for why
   the JS-owned detent machinery died. What changes with the viewport is only
   dressing: edge-to-edge with safe-area padding below ~40rem, a floating
   rounded tray above.

   WHY THIS IS ITS OWN FILE. Propshaft loads the stylesheets alphabetically
   under the bulk `stylesheet_link_tag :app` (shared/_head), so
   `wizard_composer.css` lands after `notarium.css`, `navbar.css` and
   `wizard.css` and wins ties without a single `!important`.

   Sections:
     1. The focus surface — what the wizard hides while it is on screen
     2. The rail
     3. The paper
     4. The composer: the tray, its fold, its two rows
     5. The controls inside it
     6. The document's own ink — anchors, targets, live slots
     7. The review and the commit bar
     8. Narrow viewports
     9. Reduced motion
   ══════════════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════════
   1. THE FOCUS SURFACE
   ══════════════════════════════════════════════════════════════════════ */

/* THE WIZARD REPLACES THE NAVBAR. Two bars of chrome over a sheet of A4 is
   one bar too many, and the rail already carries the brand, the selskab, the
   event and the way out — which is everything the navbar was doing here.

   Done with `:has()` rather than a body class, because the layout is shared
   with forty other screens and none of them should have to know that a wizard
   exists. */
body.nt-app:has(.nt-wz) > .nt-navbar,
body.nt-app:has(.nt-wz) > .nt-mobile-scrim,
body.nt-app:has(.nt-wz) > .nt-mobile-panel { display: none; }

/* The page container gives up its measure and its padding: the stage is the
   viewport, and the paper centres itself inside it. */
body.nt-app:has(.nt-wz) > .nt-app-main { padding: 0; overflow-x: visible; }

.nt-app-column:has(.nt-wz) { max-width: none; margin: 0; }

/* The chat launcher stays in the BOTTOM RIGHT CORNER, wizard or no wizard.
   It used to be lifted 8.5rem "out of the resting tray's way" — but the tray
   is centred at 52rem and fits its content now, so the lift just parked the
   bubble in mid-air beside the tray's middle. The corner is where every chat
   bubble on the internet lives; at the rare width where the tray's corner and
   the bubble overlap, the bubble's higher z-index keeps it clickable. */

.nt-wz {
  --nt-wz-rail-h: 3rem;
  /* The paper's measure, and the composer's. They are the same number on
     purpose: a tray narrower than the sheet reads as a widget floating over a
     document, and a tray as wide as the sheet reads as the document's own
     writing surface. */
  --nt-wz-measure: 52rem;

  /* THERE ARE NO DETENTS. The tray is `height: auto` under the caps below —
     the stylesheet owns the height entirely, and the controller only folds.
     This token is the PAPER'S clearance: the stage keeps this much room at
     the bottom so the last clause of a document can be scrolled clear of the
     tallest tray a roomy screen can stand. */
  --nt-wz-clearance: min(82dvh, 46rem);

  position: relative;
  min-height: 100dvh;
  background: var(--nt-bg);
}

/* ══════════════════════════════════════════════════════════════════════
   2. THE RAIL
   ══════════════════════════════════════════════════════════════════════ */

.nt-wz-rail {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 40;
  height: var(--nt-wz-rail-h);
  display: flex;
  align-items: center;
  gap: var(--nt-space-5);
  padding: 0 var(--nt-space-4);
  /* Translucent over the paper, so the sheet visibly runs UNDER the rail
     rather than stopping at it. The document is the page; the rail is glass
     laid on top. */
  background: color-mix(in oklab, var(--nt-surface) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--nt-border-subtle);
}

.nt-wz-brand {
  display: flex;
  align-items: center;
  gap: var(--nt-space-2);
  flex: none;
  min-width: 0;
  color: inherit;
  text-decoration: none;
  /* A hover pill, so the cluster reads as the LINK it is — the wizard felt
     like a surface you could not leave (Marcus). The negative margin keeps
     the mark optically where it stood before the padding. */
  padding: 0.3rem 0.55rem 0.3rem 0.4rem;
  margin-left: -0.4rem;
  border-radius: var(--nt-radius);
  transition: background var(--nt-duration-fast) var(--nt-ease);
}

.nt-wz-brand:hover { background: var(--nt-bg-accent); }

.nt-wz-brand:hover .nt-wz-brand-event { color: var(--nt-seal); }

/* The chevron says "back" before anybody hovers; on hover it leans out. */
.nt-wz-brand-back {
  display: grid;
  place-items: center;
  color: var(--nt-text-tertiary);
  transition: color var(--nt-duration-fast) var(--nt-ease),
              transform var(--nt-duration-fast) var(--nt-ease);
}

.nt-wz-brand:hover .nt-wz-brand-back { color: var(--nt-seal); transform: translateX(-2px); }

.nt-wz-brand-text { display: grid; min-width: 0; line-height: 1.15; }

.nt-wz-brand-event {
  font-size: var(--nt-text-sm);
  font-weight: 600;
  letter-spacing: 0.005em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color var(--nt-duration-fast) var(--nt-ease);
}

.nt-wz-brand-company {
  font-size: 0.66rem;
  color: var(--nt-text-tertiary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── the track ──────────────────────────────────────────────────────────── */

/* The region's slot in the rail ROW now holds only the jump ("4/12 · Dirigent
   ▾"); the trail itself hangs below the rail's edge. */
.nt-wz-track {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
}

/* TRUE CENTRE, not flex-slot centre. The brand and the right-hand controls
   are different widths, so centring inside the leftover slot put the jump —
   and visually its popover, which is fixed at 50vw — off the document's own
   axis. Absolute against the fixed rail, the trigger, the popover and the
   paper all share one centreline. */
.nt-wz-jump {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  max-width: min(24rem, 40vw);
}

.nt-wz-jump-label { overflow: hidden; text-overflow: ellipsis; }

/* THE TRAIL — the progress strip, hugging the rail's bottom border edge to
   edge. Absolutely positioned against the fixed rail (the header is its
   containing block), so it spans the viewport whatever the region's flex slot
   measures. One button: the whole strip opens the step list, and the padding
   grows the 4px paint into a findable target. */
.nt-wz-trail {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  display: flex;
  gap: 2px;
  height: 4px;
  padding: 0 0 6px; /* invisible hit area below the paint */
  box-sizing: content-box;
  background: none;
  border: 0;
  cursor: pointer;
}

.nt-wz-trail:focus-visible { outline: none; box-shadow: var(--nt-shadow-focus); }

/* A breath of presence on approach: the strip thickens under the pointer. */
.nt-wz-trail:hover .nt-wz-seg { transform: scaleY(1.5); }

.nt-wz-seg {
  flex: 1;
  height: 4px;
  transform-origin: top;
  background: var(--nt-border-subtle);
  transition: background var(--nt-duration-slow) var(--nt-ease),
              box-shadow var(--nt-duration-slow) var(--nt-ease),
              transform var(--nt-duration-fast) var(--nt-ease);
}

/* The strip's outer corners follow the viewport, not each segment. */
.nt-wz-seg:first-child { border-radius: 0 0 0 2px; }
.nt-wz-seg:last-child { border-radius: 0 0 2px 0; }

.nt-wz-seg[data-state="done"] { background: var(--nt-seal); opacity: 0.85; }

/* The one saturated moment on the trail: "you are here" glows softly below
   its own segment. */
.nt-wz-seg[data-state="here"] {
  background: var(--nt-seal);
  box-shadow: 0 2px 8px var(--nt-seal-tint), 0 1px 3px var(--nt-seal-border);
}

/* AMBER, NEVER RED. Red in this design system means overdue; a question you
   chose not to answer is not a failure. */
.nt-wz-seg[data-state="skipped"] { background: var(--nt-warn); opacity: 0.7; }

/* SOMEBODY ELSE IS ANSWERING THIS ONE. Dotted rather than filled, and
   deliberately NOT the amber above: a question handed to the revisor is behind
   the gap and unanswered, which is the letter of "skipped" and the opposite of
   its meaning. The segment reads as a line still being drawn — nothing is
   wrong, we are waiting. (Wizards::Delegations; the name is in the popover,
   because 4px of strip cannot carry one.) */
.nt-wz-seg[data-state="delegated"] {
  background: repeating-linear-gradient(
    to right,
    var(--nt-seal-border) 0 3px,
    transparent 3px 6px
  );
}

.nt-wz-seg[data-state="next"] { background: var(--nt-seal-border); }

/* Held back for its turn in the cascade — see wizard_progress_controller. */
.nt-wz-seg[data-state="pending"] { background: var(--nt-border-subtle); }

/* WHERE A CHAPTER BEGINS. One hairline gap in the strip — no colour, no rule,
   no label: the chapter's name is in the jump above it, and a 4px band is no
   place for typography. It is the trail's only punctuation, so it has to read
   as a breath rather than as a break. */
.nt-wz-seg[data-chapter-start] { margin-left: 5px; }

/* THE OPENING SCREEN, as a dot in front of the track. Fixed width and
   `flex: none`, so it takes no share of the questions' strip — it is not one
   of them — and the trail still has something lit while the customer stands on
   "Sådan foregår det". */
.nt-wz-intro-dot {
  flex: none;
  width: 4px;
  height: 4px;
  margin-right: 5px;
  border-radius: 0 0 0 2px;
  background: var(--nt-border-subtle);
  transition: background var(--nt-duration-slow) var(--nt-ease);
}
.nt-wz-intro-dot[data-state="done"] { background: var(--nt-seal); opacity: 0.85; }
.nt-wz-intro-dot[data-state="here"] {
  background: var(--nt-seal);
  box-shadow: 0 2px 8px var(--nt-seal-tint), 0 1px 3px var(--nt-seal-border);
}

.nt-wz-jump {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.3rem 0.6rem;
  border: 0;
  border-radius: var(--nt-radius);
  background: transparent;
  color: var(--nt-text);
  font-family: var(--nt-font-body);
  font-size: var(--nt-text-sm);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--nt-duration-fast) var(--nt-ease);
}
.nt-wz-jump:hover, .nt-wz-jump[aria-expanded="true"] { background: var(--nt-surface-raised); }
.nt-wz-jump svg { color: var(--nt-text-secondary); }
.nt-wz-jump-count {
  font-family: var(--nt-font-mono);
  font-size: 0.66rem;
  font-weight: 500;
  color: var(--nt-text-secondary);
  font-variant-numeric: tabular-nums;
}
/* The tabs wrapper is a stream REGION, not a layout box. */
.nt-wz-tabs-region { display: contents; }

/* ── the step popover ───────────────────────────────────────────────────── */

.nt-wz-steps {
  position: fixed;
  top: calc(var(--nt-wz-rail-h) + 0.4rem);
  left: 50%;
  transform: translateX(-50%);
  width: min(26rem, calc(100vw - 2rem));
  max-height: 70dvh;
  overflow: auto;
  z-index: 50;
  padding: var(--nt-space-2);
  background: var(--nt-surface-overlay);
  border: 1px solid var(--nt-border-subtle);
  border-radius: var(--nt-radius-lg);
  box-shadow: var(--nt-shadow-3);
  animation: nt-wz-pop var(--nt-duration) var(--nt-ease) both;
}

@keyframes nt-wz-pop {
  from { opacity: 0; transform: translateX(-50%) translateY(-4px); }
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}

.nt-wz-steps-group {
  font-family: var(--nt-font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--nt-text-tertiary);
  padding: var(--nt-space-3) var(--nt-space-3) var(--nt-space-1);
  margin: 0;
}

.nt-wz-steps-list { list-style: none; margin: 0; padding: 0; }

.nt-wz-step-row {
  display: flex;
  align-items: flex-start;
  gap: var(--nt-space-3);
  width: 100%;
  padding: 0.45rem var(--nt-space-3);
  border-radius: var(--nt-radius);
  font-size: var(--nt-text-sm);
  color: var(--nt-text-secondary);
  text-decoration: none;
  text-align: left;
}

.nt-wz-step-row:hover { background: var(--nt-bg-accent); color: var(--nt-text); }
.nt-wz-step-row:focus-visible { outline: none; box-shadow: var(--nt-shadow-focus); }

.nt-wz-step-mark {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin-top: 0.1rem;
  border-radius: var(--nt-radius-full);
  border: 1.5px solid var(--nt-border);
  display: grid;
  place-items: center;
  font-size: 0.56rem;
  font-variant-numeric: tabular-nums;
  color: var(--nt-text-tertiary);
}

.nt-wz-step-label { display: block; font-weight: 600; color: var(--nt-text); }

/* The whole question, on the second line. This is the payoff for taking the
   names off the rail: there is room here to print what was being truncated. */
.nt-wz-step-question {
  display: block;
  font-size: var(--nt-text-xs);
  color: var(--nt-text-tertiary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nt-wz-step-row[data-state="done"] .nt-wz-step-mark {
  background: var(--nt-seal);
  border-color: var(--nt-seal);
  color: var(--nt-on-seal);
}

.nt-wz-step-row[data-state="here"] {
  background: var(--nt-seal-soft);
  color: var(--nt-text);
}

.nt-wz-step-row[data-state="here"] .nt-wz-step-mark {
  border-color: var(--nt-seal);
  color: var(--nt-seal);
}

.nt-wz-step-row[data-state="skipped"] .nt-wz-step-mark {
  border-color: var(--nt-warn);
  color: var(--nt-warn-text);
  border-style: dashed;
}

.nt-wz-step-row[data-state="ahead"] .nt-wz-step-mark { border-style: dashed; }

/* The delegated row, and the one line only the popover has room for: "Sendt
   til Sofie Krogh". Dotted like its segment, and in the neutral ink — the
   question is not overdue, not skipped and not wrong. */
.nt-wz-step-row[data-state="delegated"] .nt-wz-step-mark { border-style: dotted; }

.nt-wz-step-delegated {
  display: block;
  font-size: var(--nt-text-xs);
  color: var(--nt-text-tertiary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── the rail's right-hand controls ─────────────────────────────────────── */

.nt-wz-rail-right { display: flex; align-items: center; gap: var(--nt-space-1); flex: none; }

/* "Bekræftes af Marcus Wilstrup" — the member seat's standing note, in the
   rail so it is on trin 1 rather than only on the commit bar at trin 20. A
   LINE, not a badge: it is a fact about how this beslutning ends, not a state
   anything is in, and colouring it would make it read as a warning about work
   the customer is doing perfectly well. It goes first on a narrow rail, where
   the names are worth more than a second copy of the document selector. */
.nt-wz-seat {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0;
  padding: 0.2rem 0.5rem;
  min-width: 0;
  font-size: var(--nt-text-xs);
  color: var(--nt-text-tertiary);
}

.nt-wz-seat > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 18ch;
}

/* Below 40rem the rail is down to the brand and the way out (§8), and a line
   that ellipsised to "Bekræftes af M…" would be a worse answer than none. The
   commit bar still says the whole sentence when the moment arrives, and the
   opening screen says it before the work starts (A-3). */
@media (max-width: 40rem) {
  .nt-wz-seat { display: none; }
}

/* THE DOCUMENT SELECTOR — a dropdown, not tabs. A stiftelse produces four
   documents; four segmented tabs ate the rail, and on a phone they were
   hidden outright. The trigger names the document on screen (the step jump's
   "name ▾" idiom); the menu drops DOWN from the fixed rail. */
.nt-wz-doc { position: relative; }

.nt-wz-doc-trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.55rem;
  border: 0;
  border-radius: 0.45rem;
  background: none;
  color: var(--nt-text-secondary);
  font-size: var(--nt-text-xs);
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--nt-duration-fast) var(--nt-ease);
}

.nt-wz-doc-trigger:hover,
.nt-wz-doc-trigger[aria-expanded="true"] { background: var(--nt-bg-accent); color: var(--nt-text); }
.nt-wz-doc-trigger:focus-visible { outline: none; box-shadow: var(--nt-shadow-focus); }

.nt-wz-doc-label {
  max-width: 11rem;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nt-wz-doc-menu {
  position: absolute;
  top: calc(100% + 0.45rem);
  right: 0;
  z-index: 50;
  min-width: 15rem;
  padding: var(--nt-space-1);
  background: var(--nt-surface-overlay);
  border: 1px solid var(--nt-border-subtle);
  border-radius: var(--nt-radius-lg);
  box-shadow: var(--nt-shadow-3);
  animation: nt-wz-doc-in var(--nt-duration) var(--nt-ease) both;
}

@keyframes nt-wz-doc-in {
  from { opacity: 0; translate: 0 -4px; }
  to { opacity: 1; translate: 0 0; }
}

.nt-wz-doc-row { display: block; }

.nt-wz-doc-option {
  display: flex;
  align-items: center;
  gap: var(--nt-space-2);
  width: 100%;
  padding: 0.45rem var(--nt-space-3);
  border: 0;
  border-radius: var(--nt-radius);
  background: none;
  color: var(--nt-text-secondary);
  font-size: var(--nt-text-sm);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}

.nt-wz-doc-option:hover { background: var(--nt-bg-accent); color: var(--nt-text); }
.nt-wz-doc-option:focus-visible { outline: none; box-shadow: var(--nt-shadow-focus); }
.nt-wz-doc-option[aria-current="true"] { color: var(--nt-text); font-weight: 600; }

/* The check column keeps the titles aligned whether or not a row carries
   the mark. */
.nt-wz-doc-mark { flex: none; width: 0.85rem; display: grid; place-items: center; color: var(--nt-seal); }

.nt-wz-zoom,
.nt-wz-close {
  display: inline-flex;
  align-items: center;
  gap: var(--nt-space-1);
  font-size: var(--nt-text-xs);
  font-weight: 500;
  color: var(--nt-text-tertiary);
  padding: 0.3rem 0.55rem;
  border: 0;
  border-radius: 0.45rem;
  background: none;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.nt-wz-zoom:hover,
.nt-wz-close:hover { background: var(--nt-bg-accent); color: var(--nt-text); }
.nt-wz-zoom:focus-visible,
.nt-wz-close:focus-visible { outline: none; box-shadow: var(--nt-shadow-focus); }

/* "Spørg en jurist" in the rail exists for phones only; the desktop has the
   chat launcher one tap away (§8 shows it). */
.nt-wz-jurist { display: none; }

/* "Deltagere" — the way to invite a medstifter, a revisor or an advokat into
   this one guide. Quiet, and only for a seat that may hand out a token
   (WizardParticipantPolicy delegates to WizardSessionPolicy#update?). */
.nt-wz-close .nt-wz-close-label { display: inline; }

/* THE WAY OUT. "Luk", with the X the rest of the system closes things with —
   everything is autosaved, so leaving is always safe and must always be
   findable. A hairline pill, so it reads as a control rather than as one
   more quiet word in a row of quiet words. */
.nt-wz-exit {
  border: 1px solid var(--nt-border-subtle);
  border-radius: var(--nt-radius-full);
  padding: 0.3rem 0.7rem;
  color: var(--nt-text-secondary);
}

.nt-wz-exit:hover { border-color: var(--nt-border); background: var(--nt-bg-accent); color: var(--nt-text); }

/* ══════════════════════════════════════════════════════════════════════
   3. THE PAPER — the page's only scroll surface
   ══════════════════════════════════════════════════════════════════════ */

.nt-wz-stage {
  position: fixed;
  inset: var(--nt-wz-rail-h) 0 0 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  display: flex;
  justify-content: center;
  /* Top: air under the rail. Bottom: room for the composer at its tallest
     resting height plus a margin, so the last clause of a document can still
     be scrolled clear of the tray. */
  padding: var(--nt-space-8) var(--nt-space-6) calc(var(--nt-wz-clearance) + var(--nt-space-8));
  background: var(--nt-bg);
}

/* The sheet takes the measure the composer takes. */
.nt-wz-stage .nt-doc-pane,
.nt-wz-stage .nt-doc-frame { width: 100%; max-width: var(--nt-wz-measure); }

.nt-wz-stage .nt-doc-frame { padding: 0; background: none; }

/* ══════════════════════════════════════════════════════════════════════
   4. THE COMPOSER
   ══════════════════════════════════════════════════════════════════════ */

.nt-wz-composer-wrap {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 45;
  display: flex;
  justify-content: center;
  /* The wrap does not take the pointer; the tray inside it does. Everything
     either side of the tray is document, and it stays clickable. */
  pointer-events: none;
  padding: 0 var(--nt-space-4) calc(var(--nt-space-4) + env(safe-area-inset-bottom, 0px));
  /* The document fades INTO the tray rather than being cut off by it. */
  background: linear-gradient(to top, var(--nt-bg) 22%, transparent);
  /* An on-screen keyboard shrinks the visual viewport without touching the
     layout one; --nt-wz-vv-shift is how much of the layout viewport it is
     standing on (written by the controller). */
  bottom: var(--nt-wz-vv-shift, 0px);
}

.nt-wz-composer {
  pointer-events: auto;
  position: relative; /* anchors the escalation band floating above the tray */
  width: 100%;
  max-width: var(--nt-wz-measure);
  display: flex;
  flex-direction: column;
  background: var(--nt-surface);
  border: 1px solid var(--nt-border-subtle);
  border-radius: var(--nt-radius-lg);
  box-shadow: var(--nt-shadow-3);
  /* NO overflow clip and NO paint containment here: the ⓘ why-popover and the
     person picker's suggestion list open OUTSIDE the tray's box (upward /
     downward), and clipping them at the tray edge cropped both. The only
     thing that must clip is the field body's own scrolling, and that clip
     lives on .nt-wz-composer-scroll. Rounded corners survive because every
     child is inset by the tray's own padding, not clipped by its border. */
  overflow: visible;

  /* CSS OWNS THE HEIGHT — `auto`, always. The controller flips `data-folded`
     and writes nothing else; the predecessor's JS-owned detents/probe/drag
     heights were three sources of truth, and every regression in the tray's
     history was two of them disagreeing. Do not reintroduce a height writer.

     The caps: a plain question may take at most ~40% of the viewport (the
     document is the page); only a screen the SERVER marked tall — a table, a
     list of people, the review, a refusal — earns the roomy cap. The
     viewport guard keeps the rail's strip and a breath of air above the tray
     at every screen size; --nt-wz-vv is the visual viewport when a keyboard
     stands on it. */
  height: auto;
  max-height: min(40dvh, 26rem, calc(var(--nt-wz-vv, 100dvh) - 9rem));
  contain: layout;
}

.nt-wz-composer:has([data-forces-full], .nt-stop) {
  max-height: min(82dvh, 46rem, calc(var(--nt-wz-vv, 100dvh) - 9rem));
}

/* ── THE FOLD ─────────────────────────────────────────────────────────────
   Two states, one attribute. `.nt-wz-fold` wraps everything under the head
   row (see _panel.html.erb): a one-track grid whose row animates 1fr ⇄ 0fr —
   the one way to animate "as tall as its content ⇄ gone" without measuring
   anything. The inner child must be allowed to shrink (min-height: 0) and
   clips what no longer fits. Folded, the tray is grip + question: a strip
   the whole of which folds back out on a click (surfaceClick). */
.nt-wz-fold {
  flex: 1 1 auto;
  display: grid;
  grid-template-rows: 1fr;
  /* The question row never collapses to a sliver while open. */
  min-height: 3.75rem;
  /* NO transition on the rows: interpolating 1fr ⇄ 0fr inside an auto-height
     grid froze in Chrome — the computed track lagged one state behind and
     the fold answered the PREVIOUS click. The snap is instant and always
     correct; the foldable's opacity fade below is the motion. */
}

.nt-wz-foldable {
  min-height: 0;
  overflow: clip;
  display: flex;
  flex-direction: column;
  transition: opacity var(--nt-duration) var(--nt-ease);
}

.nt-wz-composer[data-folded] .nt-wz-foldable { opacity: 0; }

.nt-wz-composer[data-folded] .nt-wz-fold {
  grid-template-rows: 0fr;
  min-height: 0;
}

.nt-wz-composer[data-folded] .nt-wz-head { padding-bottom: var(--nt-space-3); }
/* The chevron is the fold's compass: down while open (press to put the
   question away), up while folded (press to bring it back). */
.nt-wz-composer[data-folded] .nt-wz-grip-chevron { color: var(--nt-seal); }
.nt-wz-composer[data-folded] .nt-wz-grip-chevron svg { transform: rotate(180deg); }
/* On the review the head row is normally traded for the commit bar — but the
   commit bar folds away with the body, and a folded strip with no words is a
   strip nobody understands. Folded, the head speaks for the screen. */
.nt-wz-composer[data-folded] .nt-wz-form:has(.nt-wz-commit) > .nt-wz-head { display: flex; }

/* ── the grip ───────────────────────────────────────────────────────────── */

/* THE FOLD CONTROL IS A SMALL CIRCLE RIDING THE TRAY'S TOP EDGE, dead
   centre (Marcus) — half above the border, half below, the way a pull-tab
   sits on a sheet's rim. Absolute, so it costs no vertical space; the
   padded box around the visible circle is the hot zone a finger actually
   hits. `touch-action: none` so a thumb-flick on it reaches the pointer
   events instead of scrolling the page. (The composer's overflow is
   `visible` — see §3 — which is what lets the top half stand outside.) */
.nt-wz-grip {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 3;
  display: grid;
  place-items: center;
  padding: 0.3rem 0.7rem;
  touch-action: none;
  cursor: pointer;
}

.nt-wz-grip-handle {
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border: 1px solid var(--nt-border-subtle);
  background: var(--nt-surface);
  padding: 0;
  cursor: inherit;
  border-radius: var(--nt-radius-full);
  box-shadow: var(--nt-shadow-1);
  transition: background var(--nt-duration-fast) var(--nt-ease),
              box-shadow var(--nt-duration-fast) var(--nt-ease);
}

.nt-wz-grip:hover .nt-wz-grip-handle { background: var(--nt-bg-accent); box-shadow: var(--nt-shadow-2); }

.nt-wz-grip-handle:focus-visible { outline: none; box-shadow: var(--nt-shadow-focus); }

.nt-wz-grip-chevron {
  display: grid;
  place-items: center;
  color: var(--nt-text-tertiary);
  transition: color var(--nt-duration-fast) var(--nt-ease);
}

.nt-wz-grip-chevron svg { transition: transform var(--nt-duration) var(--nt-ease); }

.nt-wz-grip-handle:hover .nt-wz-grip-chevron { color: var(--nt-text); }

/* ── the scroll region ──────────────────────────────────────────────────── */

/* NOTHING SCROLLS OUT HERE. The question and the buttons are the two things
   that must never leave the screen — a customer looking at the fourth field of
   a screen still has to know what was asked and still has to be able to press
   Næste. So the outer wrapper only distributes height; the ONE scroll surface
   inside the composer is `.nt-wz-controls`, the field body itself.

   `min-height: 0` on every link in the chain: a flex item's default
   `min-height: auto` refuses to shrink below its content, which silently
   turns "the fields scroll" into "the composer grows past the viewport".

   `flex: 1 1 auto`, NOT `flex: 1` — the basis is the load-bearing third
   value. Under the auto-height composer a zero basis collapses the whole
   chain to nothing (this is why the old controller needed a measuring
   probe); basis auto sizes the tray to its content, and min-height: 0 still
   lets the chain shrink when the max-height cap binds. */
.nt-wz-composer-scroll {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* NO clip here either: the head row — and the ⓘ popover that opens UP from
     it — lives inside this wrapper, so an overflow: hidden at this level
     cropped the popover at the tray's top edge exactly like the composer's
     old clip did. The only things that scroll are .nt-wz-controls and the
     escalation band, and each carries its own overflow-y: auto. */
  overflow: visible;
}

/* #wizard-panel sits between the composer and the form and is the Turbo Stream
   target, so it cannot be removed from the chain — it passes the height
   through instead. */
.nt-wz-composer-scroll > #wizard-panel {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.nt-wz-form {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}

.nt-wz-head { flex: none; }

/* ── the head row: count · question · autosave · why ────────────────────── */

.nt-wz-head {
  flex: none;
  display: flex;
  /* TOP-ALIGNED WITH ONE SHARED LINE BOX, not `baseline`: the count is a
     mono face whose baseline sits differently from the display face, and the
     ⓘ is a circle with no baseline at all — mixing them left every element
     at its own height (Marcus). --nt-wz-qline is the question's first-line
     box; the count adopts it and the circle centres on it, so the row reads
     as ONE line whatever the question's length. */
  --nt-wz-qline: calc(0.92rem * 1.35);
  align-items: flex-start;
  gap: var(--nt-space-2);
  /* Top: clears the lower arc of the fold circle straddling the tray's top
     border, so a long first line never runs under it. */
  padding: 1.05rem var(--nt-space-4) 0.3rem;
}

.nt-wz-qcount {
  flex: none;
  font-family: var(--nt-font-mono);
  font-size: 0.62rem;
  line-height: var(--nt-wz-qline);
  color: var(--nt-text-tertiary);
  font-variant-numeric: tabular-nums;
}

.nt-wz-question {
  /* Natural width, shrinkable: the ⓘ stands at the END of the sentence it
     explains, and the autosave whisper takes the leftover to the right. */
  flex: 0 1 auto;
  min-width: 0;
  margin: 0;
  font-family: var(--nt-font-body);
  font-size: 0.92rem;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.005em;
  color: var(--nt-text);
}

.nt-wz-question:focus-visible { outline: none; text-decoration: underline; text-underline-offset: 4px; }

.nt-wz-formal {
  font-family: var(--nt-font-mono);
  font-size: 0.55rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--nt-text-tertiary);
  margin-right: var(--nt-space-2);
}

.nt-wz-head .nt-autosave {
  flex: none;
  margin-left: auto;
  /* Same line as the question's first line (the whisper is 1.2rem tall). */
  margin-top: calc((var(--nt-wz-qline) - 1.2rem) / 2);
}

/* ── the why popover ────────────────────────────────────────────────────── */

.nt-wz-why {
  flex: none;
  position: relative;
  /* The 1.55rem circle, optically centred on the question's first line. */
  margin-top: calc((var(--nt-wz-qline) - 1.55rem) / 2);
}

.nt-wz-why-btn {
  display: grid;
  place-items: center;
  width: 1.55rem;
  height: 1.55rem;
  border-radius: var(--nt-radius-full);
  border: 1px solid var(--nt-border-subtle);
  background: none;
  color: var(--nt-text-tertiary);
  cursor: pointer;
  transition: color var(--nt-duration-fast) var(--nt-ease),
              border-color var(--nt-duration-fast) var(--nt-ease),
              background var(--nt-duration-fast) var(--nt-ease);
}

.nt-wz-why-btn:hover,
.nt-wz-why-btn[aria-expanded="true"] {
  color: var(--nt-seal);
  border-color: var(--nt-seal-border);
  background: var(--nt-seal-soft);
}

.nt-wz-why-btn:focus-visible { outline: none; box-shadow: var(--nt-shadow-focus); }

/* Dark, because it is an aside: the § and its paragraph are a footnote laid
   over the product, not another panel of it. */
.nt-wz-why-pop {
  position: absolute;
  left: 0;
  bottom: calc(100% + 0.55rem);
  z-index: 60;
  width: min(22rem, 82vw);
  padding: var(--nt-space-3) var(--nt-space-4);
  background: var(--nt-c-ink-900);
  color: var(--nt-c-paper-100);
  border-radius: 0.8rem;
  box-shadow: var(--nt-shadow-3);
  font-size: 0.78rem;
  line-height: 1.55;
  animation: nt-wz-why-in var(--nt-duration) var(--nt-ease) both;
}

@keyframes nt-wz-why-in {
  from { opacity: 0; translate: 0 4px; }
  to { opacity: 1; translate: 0 0; }
}

.nt-wz-why-head { display: flex; align-items: center; gap: var(--nt-space-2); flex-wrap: wrap; }

/* The § chip inverts inside the dark panel — the shared component's paper
   ground would be a white brick on ink. */
.nt-wz-why-pop .nt-law-chip {
  background: rgb(255 255 255 / 0.12);
  border-color: transparent;
  color: inherit;
}

.nt-wz-why-majority { font-size: 0.7rem; opacity: 0.75; }

.nt-wz-why-body { margin: var(--nt-space-2) 0 0; }

/* ── the body row: back · control · next ────────────────────────────────── */

.nt-wz-body {
  flex: 1 1 auto;
  /* THE QUESTION ROW NEVER GIVES WAY. The band above it (flex: none,
     internally scrolling, capped) is the shrinkable party; this floor keeps
     the field row real when the composer's cap squeezes the column. */
  min-height: 3.75rem;
  display: flex;
  /* THE FIELD STACK FLOWS FROM THE TOP, under the head row.
   *
   * This was `align-items: flex-end`, chosen so Næste would sit at the bottom
   * of a grown composer. On a one-field screen it did something much worse: the
   * body row is `flex: 1`, so it is as tall as the detent, and bottom-aligning
   * pushed the single control to the floor with 250px of empty tray above it.
   * The customer got a question, a void, and then the answer — on gf_dirigent,
   * which is the screen this whole design was approved on.
   *
   * `stretch` lets the controls column take the row's full height and lay its
   * fields out from the top; the two buttons opt out of the stretch below and
   * choose their own line. */
  align-items: stretch;
  gap: var(--nt-space-2);
  padding: 0.55rem var(--nt-space-4) var(--nt-space-3);
  border: 0;
  margin: 0;
}

/* DOM ORDER IS THE ENTER KEY — "Næste" is written first so implicit submission
   fires it rather than "Tilbage". `order` puts it back on the right. */
/* The buttons line up with the FIRST field, which is where the customer is
   looking on the screens that are two rows tall — and the composer is two rows
   tall by design. */
.nt-wz-submit { order: 3; flex: none; align-self: flex-start; }
.nt-wz-back { order: 1; align-self: flex-start; }
.nt-wz-controls {
  order: 2;
  flex: 1;
  min-width: 0;
  /* THE FIELD IS NEVER THE THING THAT GIVES WAY. flex: 1 grows from a zero
     basis, so when the escalation band's auto basis filled the tray the
     controls got the 2px that were left and the question vanished. This floor
     forces the redistribution: the band (flex: 0 1 auto + overflow-y: auto)
     is the shrinkable, internally-scrolling party. */
  min-height: 3.25rem;
}

/* THE ACTIONS ARE A FOOTER ROW, ALWAYS. Every side-column variant tried —
   beside the first field, bottom-aligned when grown, conditional on field
   count — produced some screen where Næste floated in a tall empty column
   belonging to nothing. Grid, not wrapped flex: wrapped rows do not
   constrain themselves to the container's height, so the footer spilled
   below the tray. Two grid rows — the fields in a scrolling minmax(0,1fr)
   cell, the buttons in an auto row that can never leave the tray. */
.nt-wz-body {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-rows: minmax(0, 1fr) auto;
  row-gap: var(--nt-space-2);
}
.nt-wz-body > .nt-wz-controls { grid-area: 1 / 1 / 2 / 4; min-height: 0; }
.nt-wz-body > .nt-wz-back { grid-area: 2 / 1 / 3 / 2; align-self: center; }
.nt-wz-body > .nt-wz-submit { grid-area: 2 / 3 / 3 / 4; align-self: center; }

.nt-wz-body:disabled .nt-wz-controls { opacity: 0.6; }
.nt-wz-body:disabled * { cursor: default; }

/* THE ONE SCROLL SURFACE INSIDE THE COMPOSER. Several fields stack and the
   stack scrolls; the question above it and the buttons beside it do not move.
   `overscroll-behavior: contain` so reaching the end of a three-field screen
   does not start scrolling the document behind the tray. */
.nt-wz-controls {
  display: flex;
  flex-direction: column;
  gap: var(--nt-space-3);
  max-height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* THE SCROLLPORT CLIPS WHAT ITS CHILDREN PAINT OUTSIDE THEMSELVES, and it
     clips on BOTH axes: `overflow-y: auto` computes overflow-x to `auto` too,
     because one axis cannot scroll while the other stays visible. The content
     then sat flush against that edge with nothing to spare.
     A chip row is the case where it shows: the first pill's rounded left cap
     was sliced off vertically — a flat stroke where the curve should be — and
     the focus ring (--nt-shadow-focus, 0 0 0 3px) was shaved off any field
     touching an edge. The `padding-block: 1px` this replaces was the same bug
     found on the vertical axis and patched two pixels short of the ring it
     was written for.
     The inset gives the paint room; the negative inline margin gives the
     position back, so the controls still start on the head row's gutter and
     nothing on any screen moves. Block needs no counter-margin: box-sizing is
     border-box, so the padding comes out of the height rather than adding
     to it. */
  padding: 3px;
  margin-inline: -3px;
}

/* One question sits on the row between the two buttons; several stack. Both
   start at the top — `justify-content: center` here was the other half of the
   void, floating a single field in the middle of whatever height the detent
   happened to be. */
.nt-wz-controls { justify-content: flex-start; }

/* "BED JERES REVISOR OM DET HER" — the quietest thing on the screen that is
   still a control. It sits under the field it is about, inside the stack, so
   it scrolls with the question rather than competing with Næste for the
   action row: the way forward here is still the button on the right. Aligned
   left and sized down to a hint, because most customers know their own
   numbers and must not be nudged towards asking somebody else. */
.nt-wz-ask {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  align-self: flex-start;
  flex: none;
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  color: var(--nt-text-tertiary);
  font-size: var(--nt-text-xs);
  text-decoration: none;
  transition: color var(--nt-duration-fast) var(--nt-ease);
}

.nt-wz-ask[href]:hover { color: var(--nt-seal); text-decoration: underline; }
.nt-wz-ask[href]:focus-visible { outline: none; box-shadow: var(--nt-shadow-focus); border-radius: 0.35rem; }

.nt-wz-ask-icon { display: grid; place-items: center; flex: none; }

/* Already asked: a statement, not an offer. It carries no hover and no
   underline because there is nothing to press. */
.nt-wz-ask.is-waiting { color: var(--nt-text-tertiary); cursor: default; }

/* THE SCROLL IS VISIBLE OR IT DOES NOT EXIST. A field clipped at the tray's
   edge with nothing to say it continues is a field nobody finds, so the mask
   fades the last few pixels of the stack — while there is something below to
   fade towards, and never otherwise.

   THE OLD GATE WAS THE FIELD COUNT — a `data-count` attribute, faded on any
   screen with more than one field — on the stated theory that "mask-image on
   a non-overflowing element fades nothing". A mask is not conditional on
   overflow: it is applied to whatever the element paints. The attribute is
   gone; nothing else read it. A three-chip row that fitted the tray perfectly had the
   bottom 20px of its chips faded to transparent and stayed that way, because
   the escape hatch (`data-scrolled="end"`) was written from the scroll
   handler and an element that cannot scroll never fires a scroll event.

   `data-overflowing` is measured, not guessed: wizard_composer_controller
   writes it when a stack arrives, when it scrolls and when the window
   resizes, and only while `scrollHeight - scrollTop - clientHeight > 1`.
   Without JS there is no fade at all, which is the safe way to be wrong. */
.nt-wz-controls[data-overflowing] {
  mask-image: linear-gradient(to bottom, #000 calc(100% - 1.25rem), transparent);
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 1.25rem), transparent);
}

.nt-wz-back {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.6rem;
  border: 0;
  border-radius: 0.65rem;
  background: none;
  color: var(--nt-text-tertiary);
  cursor: pointer;
  transition: background var(--nt-duration-fast) var(--nt-ease),
              color var(--nt-duration-fast) var(--nt-ease);
}

.nt-wz-back:hover { background: var(--nt-bg-accent); color: var(--nt-text); }
.nt-wz-back:focus-visible { outline: none; box-shadow: var(--nt-shadow-focus); }

.nt-wz-next {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  height: 2.6rem;
  padding: 0 1.15rem;
  border: 0;
  border-radius: 0.7rem;
  background: var(--nt-seal);
  color: var(--nt-on-seal);
  font-size: 0.88rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--nt-duration-fast) var(--nt-ease),
              transform var(--nt-duration-fast) var(--nt-ease);
}

.nt-wz-next:hover { background: var(--nt-seal-hover); color: var(--nt-on-seal); }
.nt-wz-next:active { transform: scale(0.98); }
.nt-wz-next:focus-visible { outline: none; box-shadow: var(--nt-shadow-focus); }

/* HELD BACK, NOT DISABLED. An unlawful answer means the server will refuse,
   and the button stays operable so pressing it re-states why rather than
   leaving a dead control on the page. */
.nt-wz-next.is-held { background: var(--nt-neutral); }
.nt-wz-next.is-held:hover { background: var(--nt-neutral-text); }

.nt-wz-kbd {
  font-family: var(--nt-font-mono);
  font-size: 0.6rem;
  font-weight: 400;
  background: rgb(255 255 255 / 0.18);
  padding: 0.1rem 0.3rem;
  border-radius: 0.3rem;
}

/* A phone has no ↵ to promise. */
@media (pointer: coarse) {
  .nt-wz-kbd { display: none; }
}

/* ── the hint line ──────────────────────────────────────────────────────── */

.nt-wz-hint {
  font-size: 0.72rem;
  line-height: 1.45;
  color: var(--nt-text-tertiary);
  margin: 0;
}

.nt-wz-hint strong { color: var(--nt-text-secondary); font-variant-numeric: tabular-nums; }

/* § 180 OVER THE LINE: amber, and only amber. The refusal itself is the hard
   stop below; this is the sentence that gets there first. */
.nt-wz-headroom[data-state="over"] { color: var(--nt-warn-text); }
.nt-wz-headroom[data-state="over"] strong { color: var(--nt-warn-text); }

.nt-wz-peek {
  display: flex;
  gap: var(--nt-space-2);
  align-items: flex-start;
  margin: 0 var(--nt-space-4) var(--nt-space-2);
  padding: var(--nt-space-2) var(--nt-space-3);
  border-radius: var(--nt-radius);
  background: var(--nt-info-soft);
  color: var(--nt-info-text);
  font-size: var(--nt-text-xs);
}

.nt-wz-peek-icon { flex: none; color: var(--nt-info); margin-top: 0.05rem; }
.nt-wz-peek-body { margin: 0; }

/* THE PEEK'S ONE CONTROL. A read-ahead screen renders the note and the way
   back to the work and nothing else — no field, so no `.nt-wz-body` grid for
   the action row to sit in. It takes the gutter the body would have given it
   and stays small, because the point of collapsing the tray here is that the
   DOCUMENT is what the customer came to look at. */
.nt-wz-foldable > .nt-wz-submit {
  flex: none;
  align-self: flex-start;
  margin: 0 var(--nt-space-4) var(--nt-space-3);
}

/* THE STOP is the tray's own top strip — in normal flow (the old absolute
   float is what slid it under the rail). A refusal outranks the question. */
.nt-wz-foldable > .nt-stop {
  order: -1;
  flex: none;
  max-height: 35vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin: var(--nt-space-1) var(--nt-space-4) var(--nt-space-2);
  background: var(--nt-surface);
  border: 1px solid var(--nt-seal-border);
  border-radius: var(--nt-radius);
}

/* THE HAND-OFF LINE'S TWO SEATS. On a question screen: the dead middle cell
   of the action grid, beside "Næste" — the message stands where the way
   forward is, without taking it. On the review: a bordered strip above the
   commit bar. The line is ALWAYS a line; its prose is the dialog. */
.nt-wz-body > .nt-handoff {
  grid-area: 2 / 2 / 3 / 3;
  align-self: center;
  min-width: 0;
  margin: 0 var(--nt-space-3);
}

.nt-wz-foldable > .nt-handoff {
  flex: none;
  order: -1;
  margin: var(--nt-space-1) var(--nt-space-4) var(--nt-space-2);
  padding: 0.5rem var(--nt-space-3);
  background: var(--nt-surface);
  border: 1px solid var(--nt-seal-border);
  border-radius: var(--nt-radius);
}

.nt-handoff > .nt-handoff-cta { margin: 0 0 0 auto; flex: none; white-space: nowrap; }

.nt-handoff-toggle {
  flex: none;
  padding: 0;
  border: 0;
  background: none;
  font-size: var(--nt-text-xs);
  font-weight: 600;
  color: var(--nt-seal-text);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  white-space: nowrap;
}

.nt-handoff-toggle:focus-visible { outline: none; box-shadow: var(--nt-shadow-focus); }


/* ══════════════════════════════════════════════════════════════════════
   5. THE CONTROLS
   ══════════════════════════════════════════════════════════════════════ */

.nt-wz-controls .nt-field {
  display: flex;
  flex-direction: column;
  gap: var(--nt-space-2);
}
/* The seam between two stacked questions: the notarium.css defaults stack a
   20px top margin on a 16px bottom one plus the flex gap — ~50px of air per
   seam in a tray that promises compactness. One gap owns the seam. */
.nt-wz-controls .nt-field { margin-block: 0; }

/* A solo control has no visible label — the question above IS the label — so
   it loses the gap a label would have needed. */
.nt-wz-controls .nt-field[data-solo] { gap: var(--nt-space-2); }

.nt-wz-controls .nt-input,
.nt-wz-controls .nt-select {
  height: 2.6rem;
  border-radius: 0.7rem;
  border-width: 1.5px;
  background: var(--nt-bg-accent);
}

.nt-wz-controls .nt-input:focus { background: var(--nt-surface); }

.nt-wz-controls .nt-textarea { border-radius: 0.7rem; border-width: 1.5px; }

/* NINETY PIXELS OF NOTHING, and where they came from.
 *
 * This set is `flex-direction: column` (notarium.css §26b), and the fix that
 * shipped first added `flex-wrap: wrap` and `flex: 1 1 12rem` to it. On a
 * COLUMN the main axis is vertical — so `flex-basis: 12rem` stopped meaning
 * "at least 12rem wide" and started meaning "12rem TALL", and every option
 * card became a 190px box with one line of text floating in it. The customer
 * saw a tinted rectangle with its label pinned to an edge.
 *
 * A choice is a ROW, full width, text-height — the same shape the mock's
 * check rows have. Three long Danish labels side by side in a 52rem tray were
 * never going to be readable anyway. The direction is stated explicitly here
 * rather than inherited, because inheriting it is what caused this. */
.nt-wz-controls .nt-choice-set {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: var(--nt-space-2);
  margin-top: 0;
}

/* The card itself is a row, not a poster: the composer is two rows tall by
   design and a 1rem inset on four options is most of it. `flex: none` so the
   card is its own content's height and nothing can stretch it again. */
.nt-wz-controls .nt-choice {
  flex: none;
  align-items: center;
  gap: var(--nt-space-2);
  padding: 0.5rem 0.7rem;
  border-radius: 0.6rem;
}

.nt-wz-controls .nt-choice input[type="radio"] { margin-top: 0; }
.nt-wz-controls .nt-choice-title { font-size: var(--nt-text-sm); }

/* The second line is the pack's own explanation of an option, and it is worth
   keeping — but it belongs at hint weight, not at body weight. */
.nt-wz-controls .nt-choice-help {
  font-size: var(--nt-text-xs);
  line-height: 1.4;
  margin-top: 0.1rem;
}

/* A card carrying a help line cannot centre its radio against two lines of
   text — it goes back to the top, where it lines up with the title. */
.nt-wz-controls .nt-choice:has(.nt-choice-help) { align-items: flex-start; }
.nt-wz-controls .nt-choice:has(.nt-choice-help) input[type="radio"] { margin-top: 0.2rem; }

/* ── the folded note field ──────────────────────────────────────────────── */

.nt-wz-note-open {
  display: inline-flex;
  align-items: center;
  gap: var(--nt-space-2);
  padding: 0.5rem 0.85rem;
  border: 1px dashed var(--nt-border);
  border-radius: 0.7rem;
  background: none;
  color: var(--nt-text-secondary);
  font-size: var(--nt-text-sm);
  cursor: pointer;
  transition: border-color var(--nt-duration-fast) var(--nt-ease),
              color var(--nt-duration-fast) var(--nt-ease);
}

.nt-wz-note-open:hover { border-color: var(--nt-seal-border); color: var(--nt-seal); }
.nt-wz-note-open:focus-visible { outline: none; box-shadow: var(--nt-shadow-focus); }

/* ── cvr ────────────────────────────────────────────────────────────────── */

.nt-wz-cvr { display: flex; flex-direction: column; gap: var(--nt-space-2); }

.nt-input-cvr { letter-spacing: 0.08em; }

.nt-wz-cvr-result {
  margin: 0;
  display: grid;
  gap: 0.1rem;
  font-size: var(--nt-text-xs);
  min-height: 1.1rem;
}

.nt-wz-cvr-result[data-state="idle"] { display: none; }
.nt-wz-cvr-result[data-state="looking"] { color: var(--nt-text-tertiary); }
.nt-wz-cvr-result[data-state="failed"] { color: var(--nt-warn-text); }

.nt-wz-cvr-name { font-weight: 600; color: var(--nt-text); }
.nt-wz-cvr-address { color: var(--nt-text-tertiary); }

.nt-wz-cvr-result[data-state="failed"] .nt-wz-cvr-name { color: var(--nt-warn-text); font-weight: 500; }

/* ── address ────────────────────────────────────────────────────────────── */

.nt-wz-address { display: grid; gap: var(--nt-space-2); }

.nt-wz-address-street { position: relative; }

.nt-wz-address-town { display: grid; grid-template-columns: 6rem 1fr; gap: var(--nt-space-2); }

/* A POPOVER, SO NOTHING IN THE TRAY CAN CUT IT. Absolutely positioned inside
   `.nt-wz-address-street` it was clipped by two ancestors that both have to
   clip — `.nt-wz-controls` scrolls, `.nt-wz-foldable` hard-clips for the fold
   — and six suggestions rendered as two and a half. In the top layer it is
   outside both, and outside the composer's `contain: layout`; the controller
   sets top/left/width/max-height off the input's own rect and follows it on
   scroll and resize. `inset: auto` and `margin: 0` undo the UA's centring,
   which would otherwise park it in the middle of the viewport. */
.nt-wz-address-list {
  position: fixed;
  inset: auto;
  z-index: 30;
  width: auto;
  max-width: none;
  max-height: 12rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin: 0;
  padding: var(--nt-space-1);
  list-style: none;
  background: var(--nt-surface-overlay);
  border: 1px solid var(--nt-border-subtle);
  border-radius: var(--nt-radius);
  box-shadow: var(--nt-shadow-2);
}

.nt-wz-address-option {
  padding: 0.35rem var(--nt-space-2);
  border-radius: var(--nt-radius-sm);
  font-size: var(--nt-text-sm);
  cursor: pointer;
}

/* Hover and keyboard land on the SAME mark. A dropdown where the mouse lights
   one row and the arrow keys light another has two cursors. */
.nt-wz-address-option:hover,
.nt-wz-address-option.is-active { background: var(--nt-seal-soft); color: var(--nt-seal); }

.nt-wz-address-none {
  padding: 0.35rem var(--nt-space-2);
  font-size: var(--nt-text-sm);
  color: var(--nt-text-tertiary);
}

/* ── share_allocation ───────────────────────────────────────────────────── */

.nt-wz-alloc-table { width: 100%; border-collapse: collapse; font-size: var(--nt-text-sm); }

.nt-wz-alloc-table th {
  text-align: left;
  font-family: var(--nt-font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--nt-text-tertiary);
  padding: 0.3rem 0;
  border-bottom: 1px solid var(--nt-border-subtle);
}

.nt-wz-alloc-table td { padding: 0.35rem 0; border-bottom: 1px solid var(--nt-border-subtle); }

.nt-wz-alloc-amount { text-align: right; font-variant-numeric: tabular-nums; }
.nt-wz-alloc-amount .nt-affix-field { margin-left: auto; max-width: 11rem; }
.nt-wz-alloc-name { color: var(--nt-text); }
.nt-wz-alloc-pct { color: var(--nt-text-tertiary); font-size: var(--nt-text-xs); width: 5rem; }

.nt-wz-alloc-table tfoot th {
  border-bottom: 0;
  border-top: 1px solid var(--nt-border);
  padding-top: var(--nt-space-2);
  text-transform: none;
  font-family: inherit;
  font-size: var(--nt-text-xs);
  letter-spacing: 0;
  color: var(--nt-text-secondary);
}

.nt-wz-alloc-table tfoot td { border-bottom: 0; border-top: 1px solid var(--nt-border); padding-top: var(--nt-space-2); }

/* THE REST LINE. Amber while it does not add up — an unfinished fordeling is
   a half-typed answer, not an overdue frist. */
.nt-wz-alloc-rest { font-weight: 600; }
.nt-wz-alloc-rest[data-state="open"],
.nt-wz-alloc-rest[data-state="over"] { color: var(--nt-warn-text); }
.nt-wz-alloc-rest[data-state="balanced"] { color: var(--nt-ok-text); }

/* ── the dropzone ───────────────────────────────────────────────────────── */

.nt-wz-drop { display: flex; flex-direction: column; gap: var(--nt-space-2); }

.nt-wz-drop-zone {
  display: flex;
  align-items: center;
  gap: var(--nt-space-3);
  padding: var(--nt-space-3);
  border: 1.5px dashed var(--nt-border);
  border-radius: 0.7rem;
  background: var(--nt-bg-accent);
  cursor: pointer;
  transition: border-color var(--nt-duration-fast) var(--nt-ease),
              background var(--nt-duration-fast) var(--nt-ease);
}

.nt-wz-drop-zone:hover { border-color: var(--nt-seal-border); }

.nt-wz-drop[data-dragging] .nt-wz-drop-zone {
  border-color: var(--nt-seal);
  border-style: solid;
  background: var(--nt-seal-soft);
}

.nt-wz-drop[data-state="attached"] .nt-wz-drop-zone {
  border-style: solid;
  border-color: var(--nt-ok-border);
  background: var(--nt-ok-soft);
}

.nt-wz-drop[data-state="failed"] .nt-wz-drop-zone { border-color: var(--nt-warn-border); }

.nt-wz-drop-icon { flex: none; color: var(--nt-text-tertiary); }
.nt-wz-drop[data-state="attached"] .nt-wz-drop-icon { color: var(--nt-ok); }

.nt-wz-drop-title { display: block; font-size: var(--nt-text-sm); font-weight: 600; color: var(--nt-text); }
.nt-wz-drop-body { display: block; font-size: var(--nt-text-xs); color: var(--nt-text-tertiary); }

/* Visually hidden, NOT `display: none` — a hidden input cannot be reached by a
   keyboard, and "vedhæft årsrapporten" is not a mouse-only feature. */
.nt-wz-drop-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.nt-wz-drop-input:focus-visible + * { box-shadow: var(--nt-shadow-focus); }

.nt-wz-drop-progress { display: flex; align-items: center; gap: var(--nt-space-2); }

.nt-wz-drop-bar {
  flex: 1;
  height: 4px;
  border-radius: var(--nt-radius-full);
  background: var(--nt-neutral-tint);
  overflow: hidden;
}

.nt-wz-drop-bar > span {
  display: block;
  height: 100%;
  width: 0;
  background: var(--nt-seal);
  transition: width var(--nt-duration) linear;
}

.nt-wz-drop-status { font-size: var(--nt-text-xs); color: var(--nt-text-tertiary); }

.nt-wz-drop-defer {
  display: flex;
  align-items: center;
  gap: var(--nt-space-2);
  font-size: var(--nt-text-xs);
  color: var(--nt-text-secondary);
}

/* ══════════════════════════════════════════════════════════════════════
   6. THE DOCUMENT'S OWN INK
   ══════════════════════════════════════════════════════════════════════ */

/* The clause this question writes. Soft, and it STAYS while the question is on
   screen: it is not a notification, it is "this is the paragraph we are
   writing". The spread shadow is what makes a tint of a bare paragraph read as
   a highlighted BLOCK rather than as a coloured line of text. */
.nt-doc .nt-doc-target {
  border-radius: 6px;
  background: var(--nt-seal-soft);
  box-shadow: 0 0 0 10px var(--nt-seal-soft);
  transition: background var(--nt-duration-slower) var(--nt-ease),
              box-shadow var(--nt-duration-slower) var(--nt-ease);
}

/* Never occluded by the composer or hidden under the rail: the scroll
   arithmetic in document_preview_controller aims for this, and scroll-margin
   is the browser's own answer for everything that scrolls it another way
   (a fragment link, find-in-page, a focus jump). */
.nt-doc [id^="klausul-"] { scroll-margin: 5rem 0 14rem; }

/* THE COMMIT FLASH — the ink drying on the answer just given — is `.nt-wz-changed`
   in wizard.css, and it stays there: it is the redline mark in the document's
   own margin, it already runs tint-to-transparent over 1400ms, and one
   animation with two owners is how a highlight quietly changes behaviour when
   somebody reorders a stylesheet. The only thing added here is the corner
   radius that lets it sit under the target tint above without a square edge
   showing through. */
.nt-doc-sheet .nt-wz-changed { border-radius: 6px; }

/* ── the live slots ─────────────────────────────────────────────────────── */

/* An empty slot is a VISIBLE BLANK, not a collapsed sentence. A paragraph that
   reflows on every keystroke is worse than one with a gap in it, and the gap
   is honest: nothing is written there yet.

   `:empty` IS THE LOAD-BEARING HALF. The server renders an unanswered slot as
   an empty span, and until the composer's controller has connected — which is
   never, on a screen whose field is not the one this slot belongs to — no
   class is added to it. Without this selector the referat read "Der var
   indkaldt til generalforsamlingen den ." with a bare full stop where a date
   is going to be. The class is what the ECHO uses when it clears a slot the
   customer has just emptied; `:empty` is what the document does on its own. */
.nt-doc [data-answer]:empty,
.nt-doc [data-answer].nt-ink-empty {
  display: inline-block;
  min-width: 9ch;
  line-height: 1.3;
  vertical-align: baseline;
  color: transparent;
  background: var(--nt-neutral-tint);
  border-bottom: 1.5px dashed var(--nt-border);
  border-radius: 2px 2px 0 0;
  user-select: none;
}

/* Wet ink: what the composer has echoed and the server has not confirmed yet.
   It is replaced wholesale by the next render, so this class never survives a
   swap — which is exactly why it may be conspicuous. */
.nt-doc [data-answer].nt-ink-live {
  display: inline-block;
  background: var(--nt-seal-soft);
  border-bottom: 1.5px solid var(--nt-seal-border);
  border-radius: 2px;
  transition: background var(--nt-duration-slow) var(--nt-ease);
}

/* ══════════════════════════════════════════════════════════════════════
   7. THE REVIEW AND THE COMMIT BAR
   ══════════════════════════════════════════════════════════════════════ */

/* THE HEAD ROW SURVIVES THE REVIEW. It used to be hidden here, because
   "14/14 · Er alt korrekt?" was the same sentence twice above "Referatet er
   klar" — but hiding the row took the autosave status with it, on the one
   screen where the customer is about to commit and most needs to know their
   answers are safely written. The head says "Gennemgang" and shows the status;
   the count is gone, because the review is not a question you are on the way
   through (see _panel.html.erb). */

.nt-wz-review {
  /* Basis auto, not 0: under the auto-height fold chain a zero basis
     collapses the review to nothing (wizard_composer.css §4). */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--nt-space-3) var(--nt-space-4) var(--nt-space-2);
  display: flex;
  flex-direction: column;
  gap: var(--nt-space-4);
}

.nt-wz-review-intro { margin: 0; font-size: var(--nt-text-sm); color: var(--nt-text-secondary); }

/* "besvaret af Sofie Krogh" — provenance, at the weight of provenance. It sits
   inside the group label so it reads as part of "this is what this screen
   said", not as a badge on the answer. */
.nt-review-author {
  font-family: var(--nt-font-body);
  font-weight: 400;
  font-size: var(--nt-text-xs);
  text-transform: none;
  letter-spacing: 0;
  color: var(--nt-text-tertiary);
  margin-left: var(--nt-space-2);
}

/* The bar. Always on screen, whatever the review above it is doing. */
/* THE DECIDE BAR. Mark · what you have · what it costs · the two buttons.
   Its whole difficulty is that opening the confirm panel adds a sentence and
   a second button to a row that was already full. */
.nt-wz-commit {
  flex: none;
  /* A GRID, NOT A FLEX ROW, because the bar has two shapes and flex only knows
     one. Closed it is a single row — mark, state, button. Open it grows a
     second row for the confirm panel, and that row has to start under the
     STATE (column 2), not under the mark: wrapping a flex row put the sentence
     out at the bar's left edge, hanging 32px left of the title it belongs to. */
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  column-gap: var(--nt-space-3);
  row-gap: var(--nt-space-3);
  padding: var(--nt-space-3) var(--nt-space-4);
  border-top: 1px solid var(--nt-border-subtle);
  background: var(--nt-surface);
}

/* Whatever the branch renders on the right — the confirm panel, the jurist
   link, the "kun en administrator" line — lands in column 3. Stated for every
   child so a new branch cannot land somewhere surprising. */
.nt-wz-commit > * { grid-row: 1; grid-column: 3; }
.nt-wz-commit > .nt-wz-commit-mark { grid-column: 1; }
.nt-wz-commit > .nt-wz-commit-text { grid-column: 2; }

/* THE TEXT BLOCK TAKES THE LEFTOVER, and used to be the only thing that gave.
   It carried a bare `min-w-0` against an action column pinned at `flex: none`,
   so opening the confirm panel — which adds a 288px sentence and a second
   button — squeezed it to 117px: "Dokumenterne er klar" broke onto two lines
   and "4 dokumenter · 1 underskriver · frister armeres automatisk" onto three,
   and the bar grew from 68px to 130px to hold the wreckage. */
.nt-wz-commit-text { min-width: 0; }

.nt-wz-commit-mark {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: var(--nt-radius-full);
  background: var(--nt-seal-soft);
  color: var(--nt-seal);
}

.nt-wz-commit-title { margin: 0; font-size: 0.95rem; font-weight: 600; color: var(--nt-text); }
.nt-wz-commit-micro { margin: 0; font-size: 0.74rem; color: var(--nt-text-tertiary); }
.nt-wz-commit-blocked { margin: 0; font-size: var(--nt-text-xs); color: var(--nt-text-secondary); max-width: 22rem; }

.nt-wz-commit-action { min-width: 0; }

/* THE CONFIRM STEP IS ITS OWN MOMENT, so it gets its own ground: a sealed
   card inside the bar rather than a sentence and two buttons loose on a row.
   It arrives on the same 4px rise the record's commit panel uses, which is
   what tells the customer the bar changed its question rather than merely
   growing.

   `:not([data-state="closed"])` and not `[data-state="open"]`: with no
   JavaScript the panel renders open and carries no state at all — see the
   deliberate inversion in wizard_commit_controller — and the one screen in
   the product where the explanation must survive a dead script is this one. */
.nt-wz-commit-panel {
  display: flex;
  align-items: center;
  gap: var(--nt-space-3);
  min-width: 0;
}

.nt-wz-commit-panel:not([data-state="closed"]) {
  padding: var(--nt-space-3);
  border: 1px solid var(--nt-seal-border);
  border-radius: var(--nt-radius);
  background: var(--nt-seal-soft);
  animation: nt-commit-in var(--nt-duration) var(--nt-ease) both;
}

/* NO RING ROUND THE PANEL. wizard_commit_controller gives it `tabindex="-1"`
   and focuses it on open — deliberately, so the sentence is announced and read
   before a finger is on the trigger — and the global rule in notarium.css
   paints anything `[tabindex]:focus-visible` with a 2px seal outline at 3px
   offset. While the panel hugged its content that was a ring round two
   controls; now that it spans the bar's whole second row it drew a maroon
   rectangle across half the composer and read as a border somebody forgot to
   remove.
   Suppressed rather than softened because there is no keyboard state to
   indicate: `tabindex="-1"` keeps the panel out of the tab order, so nothing
   ever lands here by tabbing. The controls inside it keep their own rings, and
   the panel appearing at all is the visible change. */
.nt-wz-commit-panel:focus,
.nt-wz-commit-panel:focus-visible { outline: none; }
.nt-wz-commit-buttons { flex: none; }

/* THE SENTENCE READS. It was --nt-text-xs in secondary grey — the smallest,
   faintest type in the bar, on the one sentence that says the decision cannot
   be taken back. Body size, ink, and the measure that keeps "Fortsæt?" off a
   line of its own. */
.nt-wz-commit-confirm {
  flex: 1 1 auto;
  margin: 0;
  min-width: 0;
  font-size: var(--nt-text-sm);
  line-height: 1.5;
  color: var(--nt-text);
}

/* OPEN, THE PANEL TAKES A ROW OF ITS OWN, from the state's column to the bar's
   right edge. `:not([data-state="closed"])` throughout, never
   `[data-state="open"]`: with no JavaScript the panel renders open and carries
   no state at all, and keyed on "open" these rules would leave the sealed card
   crushed into the narrow third column on the one screen whose explanation
   must survive a dead script. A sentence and two buttons do not fit beside the state: pinned
   at `flex: none` on one row the panel took 620 of 831px and left the text
   block 117, which broke "Dokumenterne er klar" onto two lines and the micro
   onto three and grew the bar from 68px to 130px. */
.nt-wz-commit:has(.nt-wz-commit-panel:not([data-state="closed"])) > .nt-wz-commit-action {
  grid-area: 2 / 2 / 3 / 4;
}

/* ONCE THE PANEL IS OPEN THE BAR IS ASKING A DIFFERENT QUESTION, so it stops
   answering the old one. The micro is the pre-commit inventory — "4
   dokumenter · 1 underskriver · frister armeres automatisk" — and the confirm
   sentence is the consequence; the inventory is still on screen in full, in
   the consequences list directly above. */
.nt-wz-commit:has(.nt-wz-commit-panel:not([data-state="closed"])) .nt-wz-commit-micro {
  display: none;
}
.nt-wz-commit-buttons { display: flex; align-items: center; gap: var(--nt-space-2); }

/* ── the signers block ──────────────────────────────────────────────────── */

.nt-wz-signers { display: flex; flex-direction: column; gap: var(--nt-space-2); }

.nt-wz-signer-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--nt-space-1); }

.nt-wz-signer {
  display: flex;
  align-items: center;
  gap: var(--nt-space-3);
  padding: var(--nt-space-2) var(--nt-space-3);
  border: 1px solid var(--nt-border-subtle);
  border-radius: var(--nt-radius);
  background: var(--nt-bg-accent);
}

.nt-wz-signer-mark { flex: none; color: var(--nt-text-tertiary); }
.nt-wz-signer-name { margin: 0; font-size: var(--nt-text-sm); font-weight: 600; color: var(--nt-text); }
.nt-wz-signer-role { margin: 0; font-size: var(--nt-text-xs); color: var(--nt-text-tertiary); }
.nt-wz-signer-email { margin-left: auto; font-size: var(--nt-text-xs); color: var(--nt-text-tertiary); }
.nt-wz-signer-input { margin-left: auto; max-width: 15rem; }

.nt-wz-signer-unknown { margin-left: auto; font-size: var(--nt-text-xs); color: var(--nt-warn-text); }

.nt-wz-signer-form { display: flex; align-items: center; justify-content: space-between; gap: var(--nt-space-3); }

/* ══════════════════════════════════════════════════════════════════════
   8. NARROW VIEWPORTS
   The same design, docked. Nothing moves in the DOM — moving #wizard-panel
   between two layouts would tear down its form and take whatever the customer
   had typed with it.
   ══════════════════════════════════════════════════════════════════════ */

@media (max-width: 40rem) {
  /* A phone gives a roomy screen almost everything; the viewport guard
     keeps the rail's strip. */
  /* 70 %, not 88: even a tall screen leaves the top of the paper in view,
     so the document the tray is writing never disappears entirely behind
     the question. The review and the tall fields scroll inside the tray. */
  .nt-wz-composer:has([data-forces-full], .nt-stop) {
    max-height: min(70dvh, calc(var(--nt-wz-vv, 100dvh) - 5rem));
  }

  .nt-wz-rail { gap: var(--nt-space-3); padding: 0 var(--nt-space-3); }
  /* The brand text and the group labels are the first things to go: on a
     phone the customer knows which selskab they are in, and the rail's job
     narrows to "where am I in this". */
  .nt-wz-brand-text,
  .nt-wz-zoom { display: none; }
  /* The doc dropdown STAYS — it is how a phone switches documents at all.
     The title goes; the file icon and the chevron are the trigger. */
  .nt-wz-doc-label { display: none; }
  /* The icon stays, the word goes: a thumb has room for one and not both. */
  /* `.nt-wz-close .nt-wz-close-label` — two classes, because the desktop rule
     that shows the label is written with two (line ~510) and a one-class
     rule here lost to it, which is why "Deltagere" and "Luk" kept their
     words on a phone and ran into the count. */
  .nt-wz-close .nt-wz-close-label { display: none; }

  /* Full-bleed paper. A phone-width sheet with 1.5rem of desk either side is
     a picture of a document; edge to edge, it is the document. */
  .nt-wz-stage { padding: var(--nt-space-3) 0 calc(7rem + var(--nt-space-8)); }
  .nt-wz-stage .nt-doc-sheet { border-radius: 0; border-inline: 0; box-shadow: none; }

  .nt-wz-composer-wrap { padding: 0; background: none; }

  .nt-wz-composer {
    border-radius: var(--nt-radius-lg) var(--nt-radius-lg) 0 0;
    border-inline: 0;
    border-bottom: 0;
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  /* Tilbage STAYS. It sits in the footer row beside Næste, not in the
     field's row, so it costs the field nothing — and a phone with no way
     back but a popover in the rail is a phone where the customer taps Luk. */

  /* The way to a human, in the rail: the launcher is covered below. */
  .nt-wz-jurist { display: inline-flex; }

/* Edge to edge, the composer meets the launcher. The question wins: the
   chat panel is one tap from the navbar on every other screen, and a
   floating button over the field somebody is typing into is not help. */
body.nt-app:has(.nt-wz) .nt-chat-launcher { display: none; }

.nt-wz-commit { flex-wrap: wrap; }
  .nt-wz-commit-action { width: 100%; }
  .nt-wz-commit-action .nt-wz-next { width: 100%; justify-content: center; }
}

/* Below the width at which A4 stops being A4, the preview reflows to the
   phone's measure rather than standing at print geometry — and a page count
   taken at a reflowed width would not match the PDF, so the paginator is
   switched off through the custom property it reads. */
@media (max-width: 65rem) {
  .nt-wz-stage { --nt-doc-paginate: 0; }
}

/* ══════════════════════════════════════════════════════════════════════
   9. REDUCED MOTION — snaps, no glides
   ══════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  .nt-wz-foldable,
  .nt-wz-seg,
  .nt-doc .nt-doc-target,
  .nt-doc [data-answer].nt-ink-live,
  .nt-wz-drop-bar > span { transition: none; }

  .nt-wz-steps,
  .nt-wz-why-pop { animation: none; }

  .nt-doc-sheet .nt-wz-changed { animation-duration: 1ms; }

  /* The stage stops smooth-scrolling; document_preview_controller already
     asks for `behavior: auto` under reduced motion, and this catches every
     other way the page can be scrolled. */
  .nt-wz-stage { scroll-behavior: auto; }
}

/* ── §10 chips on a screen ─────────────────────────────────────────────────
   A screen whose fields are chips (`presentation: chips` on the screen) lays
   its fields out in ONE ROW: three toggle chips for "var der andet på
   mødet?" sit side by side and wrap on a phone, instead of stacking as three
   controls. `:has()` rather than an attribute on the controls box, so the
   panel does not need to know about presentations. */
.nt-wz-controls:has(> .nt-field[data-presentation="chips"]) {
  display: flex;
  /* The multi-field rule above stacks fields in a column; a chip row is the
     one multi-field screen that lies the other way. */
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.nt-wz-controls > .nt-field[data-presentation="chips"] {
  width: auto;
  margin: 0;
}

.nt-wz-controls > .nt-field[data-presentation="chips"] .nt-chips { margin-top: 0; }

/* ── §11 the opening screen ───────────────────────────────────────────────
   "Sådan foregår det": what we write, what you need, how long, what happens
   after. Reads as a short page inside the tray; earns the roomy cap through
   its own data-forces-full.

   IT IS A COVER NOTE, NOT A FORM. The first pass laid the four facts out as
   four labelled blocks — mono eyebrow over 13px grey, four times — which put
   the loudest type on the card on the CHROME and left the content flat and
   the bottom-right quadrant empty. Three things fix that and they are the
   whole design:

     * The lede is set in the document's serif at reading size. This screen
       stands directly under a Stiftelsesdokument in the same face, and it is
       the only screen in the guide that is prose rather than a question.
     * The facts on the right became one raised object (the spec panel), so
       the wide half of the tray holds something instead of air, and the
       count gets to be the biggest number on the screen.
     * Two eyebrows, not four. "Det tager" over "17 korte spørgsmål" and "Når
       I bekræfter" over "Når I bekræfter, …" were labels that repeated their
       own content. */
.nt-wz-intro {
  display: flex;
  flex-direction: column;
  gap: var(--nt-space-3);
  /* THE SAME GUTTER THE HEAD ROW KEEPS. This block used to run edge to edge —
     the question above it is inset by --nt-space-4 and the intro was not, so
     every line on the screen started 16px left of the heading that introduced
     it. Plain grey text hid it; the spec panel, which has a fill and a border,
     put its right edge flush against the tray's own and made the tray look
     broken. */
  padding: var(--nt-space-1) var(--nt-space-4) var(--nt-space-2);
}

/* Source Serif, the paper's own face (--nt-font-serif) — one step up from the
   body text and no more. At --nt-text-lg over a 44ch measure this ran three
   deep and turned the tray into a poster; the serif alone is enough to mark it
   as prose, and 56ch lands it on two lines. */
.nt-wz-intro-lede {
  margin: 0;
  max-width: 56ch;
  font-family: var(--nt-font-serif);
  font-size: 1.04rem;
  font-weight: 400;
  line-height: 1.45;
  letter-spacing: -0.003em;
  color: var(--nt-text);
}

.nt-wz-intro-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr);
  gap: var(--nt-space-5);
  align-items: start;
}

/* One column under a narrow tray — the phone composer, and the desktop tray
   whenever the guide is running beside a wide document. */
@media (max-width: 46rem) {
  .nt-wz-intro-body { grid-template-columns: minmax(0, 1fr); }
}

.nt-wz-intro-needs { min-width: 0; }

.nt-wz-intro-needs .nt-eyebrow { margin-bottom: 0.5rem; }

/* Tailwind's reset takes the marker off every ul, so this list kept its
   1.1rem indent with nothing standing in it: four sentences that read as a
   paragraph someone had accidentally tabbed.

   A SMALL FILLED DISC, not the labour split's hollow ring. The ring carries a
   STATE there (hollow = later, filled = now, tick = done) and it earns its
   11px beside its siblings; borrowed onto a list with no states it is an
   unchecked radio button, and "I skal bruge" then reads as four things to
   tick off rather than four things to have at hand. Tertiary, not
   border-strong: at this size the border tone is dust on white. */
.nt-wz-intro-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.38rem;
  font-size: var(--nt-text-sm);
  line-height: 1.45;
  color: var(--nt-text);
}

.nt-wz-intro-list li {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
}

.nt-wz-intro-list li::before {
  content: "";
  flex: none;
  width: 0.25rem;
  height: 0.25rem;
  /* On the first line's optical centre, not its top — a list whose items wrap
     otherwise hangs its dots a shade high. */
  margin-top: 0.52em;
  border-radius: var(--nt-radius-full);
  background: var(--nt-text-tertiary);
}

/* ── the spec panel ─────────────────────────────────────────────────────── */

.nt-wz-intro-spec {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--nt-space-2);
  padding: var(--nt-space-3);
  border: 1px solid var(--nt-border-subtle);
  border-radius: var(--nt-radius);
  background: var(--nt-surface-raised);
}

/* The number is what a customer takes off this screen, so it is the largest
   thing on the card after the lede — display face, ink, no label. */
.nt-wz-intro-count {
  margin: 0;
  font-family: var(--nt-font-display);
  font-size: var(--nt-text-base);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--nt-text);
}

.nt-wz-intro-qualifiers {
  margin: 0.2rem 0 0;
  font-size: var(--nt-text-sm);
  line-height: 1.4;
  color: var(--nt-text-secondary);
}

.nt-wz-intro-admin {
  margin: 0.5rem 0 0;
  font-size: var(--nt-text-xs);
  line-height: 1.45;
  color: var(--nt-text-secondary);
}

/* A hairline rather than a gap: the panel holds two unrelated facts (how big
   the job is, who has to sign) and the rule is what stops the second reading
   as a continuation of the first. */
.nt-wz-intro-signers {
  padding-top: var(--nt-space-2);
  border-top: 1px solid var(--nt-border-subtle);
}

.nt-wz-intro-signers .nt-eyebrow { margin-bottom: 0.3rem; }

.nt-wz-intro-signers p {
  margin: 0;
  font-size: var(--nt-text-sm);
  line-height: 1.45;
  color: var(--nt-text);
}

.nt-wz-intro-signers p + p { margin-top: 0.3rem; }

/* ── the foot ───────────────────────────────────────────────────────────── */

/* The after-sentence and the button share the band. Alone, the button sat in
   a hairlined strip of pure white with nothing else in it — the emptiest part
   of a screen that already had too much empty in it. */
.nt-wz-intro-foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--nt-space-4);
  flex-wrap: wrap;
  padding-top: var(--nt-space-2);
  border-top: 1px solid var(--nt-border-subtle);
}

.nt-wz-intro-after {
  flex: 1 1 22rem;
  margin: 0;
  max-width: 56ch;
  font-size: var(--nt-text-sm);
  line-height: 1.45;
  color: var(--nt-text-secondary);
}

.nt-wz-intro-actions {
  flex: none;
  margin-left: auto;
}
