.kc-button {
  display: inline-flex;
  --kc-button-min-size: var(--kc-control-min-size);
  min-block-size: var(--kc-button-min-size);
  inline-size: fit-content;
  align-items: center;
  justify-content: center;
  gap: var(--kc-space-2);
  padding: calc(var(--kc-space-2) + 2px) var(--kc-space-5);
  border: 1px solid transparent;
  border-block-end: var(--kc-key-edge-width) solid transparent;
  border-radius: var(--kc-radius-key);
  color: var(--kc-color-text);
  font-family: var(--kc-font-body);
  font-size: var(--kc-font-size-sm);
  font-weight: var(--kc-font-weight-label);
  /* The Label role's leading is 1.45, and this is the one place it is not used.
     At 0.875rem that makes the content box 20.3px, which with 10px padding and
     the 1px/4px borders totals 45.3px — past `--kc-control-min-size`. The button
     would then size to its content instead of to the 44px floor, and the press
     depends on `min-block-size` pinning the border box while the wall
     compresses. Tighter leading is what keeps that floor doing its job. */
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition:
    transform var(--kc-duration-press) var(--kc-ease-press),
    border-block-end-width var(--kc-duration-press) var(--kc-ease-press),
    background-color var(--kc-duration-press) var(--kc-ease-press);
}

/* The small size carries Micro type, not a shrunken Label. Weight has to be
   restated: inheriting the Label weight from `.kc-button` would leave a small
   button lighter than a regular one, which is backwards — at 0.75rem there is
   less stroke to read, not more. Micro's leading of 1 is safe here because 12px
   of content plus 8px padding and the borders stays under the 36px floor. */
.kc-button[data-size="small"] {
  --kc-button-min-size: 36px;
  padding: var(--kc-space-2) var(--kc-space-3);
  font-size: var(--kc-font-size-xs);
  font-weight: var(--kc-font-weight-micro);
  line-height: var(--kc-line-height-micro);
}

.kc-button[data-variant="primary"] {
  border-block-end-color: var(--kc-color-key-edge);
  background: var(--kc-color-key-face);
  color: var(--kc-color-on-key);
}

.kc-button[data-variant="primary"][data-hovered] {
  background: var(--kc-color-key-face-hover);
}

.kc-button[data-variant="secondary"] {
  border-color: var(--kc-color-border);
  border-block-end-color: var(--kc-color-border);
  background: var(--kc-color-surface-raised);
}

.kc-button[data-variant="secondary"][data-hovered],
.kc-button[data-variant="quiet"][data-hovered] {
  background: var(--kc-color-surface-hover);
}

.kc-button[data-variant="quiet"] {
  border-color: transparent;
  border-block-end-color: transparent;
  background: transparent;
  color: var(--kc-color-link);
}

/* The destructive key. Outlined rather than filled, and the reasoning lives with
   the tokens it reads — see `--kc-color-key-face-danger`. It keeps the wall and
   the travel, so the Pressable Edge Rule's promise holds. */
.kc-button[data-variant="danger"] {
  border-color: var(--kc-color-danger-border);
  border-block-end-color: var(--kc-color-key-edge-danger);
  background: var(--kc-color-key-face-danger);
  color: var(--kc-color-on-key-danger);
}

.kc-button[data-variant="danger"][data-hovered] {
  background: var(--kc-color-key-face-danger-hover);
}

.kc-button[data-variant="danger"][data-pressed]:not([data-disabled]) {
  background: var(--kc-color-key-face-danger-pressed);
  color: var(--kc-color-on-key-danger-pressed);
}

/* Every glyph is a filled Phosphor shape painting with `currentColor`, so this
   stylesheet sizes icons and never paints them. That is why there is no longer a
   rule stroking an icon-only glyph: an outline glyph needed CSS to become
   visible, and one that carries its own fill does not. It renders in markup this
   stylesheet never reaches, which is the whole point — a status carrier that
   depends on a second file to appear is not a carrier. */

/* The destructive key's shape carrier. Sized a step under the icon-only glyph so
   it reads as a mark on the label rather than as a second label, and `flex: none`
   so a long label cannot squeeze it toward nothing. */
.kc-button__tone-icon {
  inline-size: 1.125rem;
  block-size: 1.125rem;
  flex: none;
}

.kc-button[data-size="small"] .kc-button__tone-icon {
  inline-size: 1rem;
  block-size: 1rem;
}

.kc-button[data-icon-only] {
  min-inline-size: var(--kc-button-min-size);
  padding-inline: var(--kc-space-2);
}

.kc-button[data-icon-only] > svg {
  inline-size: 1.25rem;
  block-size: 1.25rem;
  flex: none;
}

/* An action that reads as a word inside a sentence.
   It is the one Button that is not a key: no surface, no wall, no control
   height, and no travel. That last part is the Pressable Edge Rule read
   correctly rather than ignored — the rule says a weighted bottom edge promises
   travel, and this variant wears none, so it owes none. A 3px hop on a run of
   text inside a paragraph would be a false note either way.

   The 44×44 target is deliberately not met, and this is the system's second
   documented exception after the `small` size. WCAG 2.5.8 exempts a target
   inside a sentence or block of text, because meeting it would mean opening the
   line height of the paragraph around it. The underline is not optional for the
   same reason the prose footnote links keep theirs: the link blue was chosen to
   sit calmly beside body text and does not clear 3:1 against it, so color alone
   cannot identify it. */
.kc-button[data-variant="link"] {
  --kc-button-min-size: 0;
  display: inline;
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: none;
  color: var(--kc-color-link);
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}

.kc-button[data-variant="link"][data-hovered] {
  background: none;
  text-decoration-thickness: 2px;
}

.kc-button[data-variant="link"][data-pressed]:not([data-disabled]) {
  transform: none;
  border-block-end-width: 0;
}

/* The press moves the key and nothing else. `min-block-size` pins the border box
   at its resting height, so compressing the wall redistributes space inside the
   box without resizing it — the only animated geometry is a transform.
   Deliberately not animating the box height: doing so relayouts every frame, and
   in a container that centers its items the key re-centers as it shrinks, which
   reads as a wobble rather than a press. */
.kc-button[data-pressed]:not([data-disabled]) {
  transform: translateY(var(--kc-press-travel));
  border-block-end-width: var(--kc-press-edge-width);
}

.kc-button[data-variant="primary"][data-pressed]:not([data-disabled]) {
  background: var(--kc-color-key-face-pressed);
}

.kc-button[data-focus-visible] {
  outline: var(--kc-focus-ring);
  outline-offset: var(--kc-focus-ring-offset);
}

.kc-button[data-disabled] {
  opacity: 0.58;
  cursor: not-allowed;
}

/* A field is three groups, not five evenly spaced lines. The label and its
   description are one unit — the description finishes the sentence the label
   starts — so they sit at step 1. The control is a change of activity, from
   reading to doing, and takes a real step away. The error binds back to the
   control it describes, closer than the control is to the text above it.
   Uniform spacing here read as five unrelated rows, and at the same step the
   card body used between whole fields, so nothing grouped and nothing separated.
   Base gap is the tightest value; the two exceptions add to it, which keeps a
   field with no description correct without a special case. */
.kc-field,
.kc-select {
  display: grid;
  inline-size: min(100%, 32rem);
  gap: var(--kc-space-1);
  color: var(--kc-color-text);
  font-family: var(--kc-font-body);
}

.kc-field__input,
.kc-select__trigger {
  margin-block-start: calc(var(--kc-space-3) - var(--kc-space-1));
}

.kc-field__error {
  margin-block-start: calc(var(--kc-space-2) - var(--kc-space-1));
}

.kc-field__label {
  display: block;
  font-size: var(--kc-font-size-sm);
  font-weight: var(--kc-font-weight-label);
}

.kc-field__description {
  color: var(--kc-color-text-muted);
  font-size: var(--kc-font-size-sm);
  line-height: var(--kc-line-height-label);
}

.kc-field__input,
.kc-select__trigger {
  inline-size: 100%;
  min-block-size: 50px;
  border: 1.5px solid var(--kc-color-border);
  border-radius: var(--kc-radius-key);
  background: var(--kc-color-surface-raised);
  color: var(--kc-color-text);
  font-family: var(--kc-font-body);
  font-size: var(--kc-font-size-md);
}

.kc-field__input {
  padding-inline: var(--kc-space-4);
}

/* A composer, not a taller input. The 50px floor is a control height; a textarea
   is a reading surface, so it takes the Body role's leading and a four-line
   floor. Resizing is block-only: a composer that can be dragged wider than the
   32rem measure its field declares breaks the Intrinsic Maximum Rule from the
   inside. `resize: block` is the logical form; `vertical` precedes it for
   engines that do not know it yet. */
.kc-field__input[data-multiline] {
  min-block-size: 6.5rem;
  padding-block: var(--kc-space-3);
  line-height: var(--kc-line-height-body);
  resize: vertical;
  resize: block;
}

.kc-field__input::placeholder {
  color: var(--kc-color-text-muted);
  opacity: 1;
}

.kc-field__input[data-hovered],
.kc-select__trigger[data-hovered] {
  border-color: var(--kc-color-text-muted);
}

.kc-field__input[data-focus-visible],
.kc-select__trigger[data-focus-visible] {
  outline: var(--kc-focus-ring);
  outline-offset: var(--kc-focus-ring-offset);
}

.kc-field[data-invalid] .kc-field__input,
.kc-select[data-invalid] .kc-select__trigger {
  border-color: var(--kc-color-danger-border);
}

.kc-field__error {
  color: var(--kc-color-danger-text);
  font-size: var(--kc-font-size-sm);
  font-weight: var(--kc-font-weight-label);
}

.kc-field__error:empty {
  display: none;
}

.kc-select__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--kc-space-3);
  padding-inline: var(--kc-space-4);
  text-align: start;
  cursor: pointer;
}

.kc-select__value[data-placeholder] {
  color: var(--kc-color-text-muted);
}

.kc-select__chevron {
  inline-size: 1.25rem;
  block-size: 1.25rem;
  flex: none;
  transition: transform var(--kc-duration-press) var(--kc-ease-press);
}

.kc-select__trigger[aria-expanded="true"] .kc-select__chevron {
  transform: rotate(var(--kc-chevron-open-turn));
}

.kc-popover,
.kc-select__popover {
  max-inline-size: min(24rem, calc(100vw - 2rem));
  border: 1px solid var(--kc-color-border);
  border-radius: var(--kc-radius-key);
  background: var(--kc-color-surface-raised);
  color: var(--kc-color-text);
  box-shadow: var(--kc-shadow-overlay);
  font-family: var(--kc-font-body);
  animation: kc-popover-in var(--kc-duration-overlay) var(--kc-ease-overlay);
}

.kc-popover {
  padding: var(--kc-space-4);
}

.kc-popover__dialog {
  outline: none;
}

.kc-popover__dialog > :first-child {
  margin-block-start: 0;
}

.kc-popover__dialog > :last-child {
  margin-block-end: 0;
}

/* A select menu matches its trigger, so the 24rem popover measure does not
   apply here — only the viewport bounds it. */
.kc-select__popover {
  inline-size: var(--trigger-width);
  min-inline-size: 12rem;
  max-inline-size: calc(100vw - 2rem);
  padding: var(--kc-space-1);
}

.kc-select__listbox {
  max-block-size: min(22rem, calc(100vh - 4rem));
  overflow: auto;
  outline: none;
}

.kc-select__option {
  display: grid;
  gap: 2px;
  padding: var(--kc-space-3);
  border-radius: calc(var(--kc-radius-key) - 3px);
  outline: none;
  cursor: default;
}

.kc-select__option [slot="label"] {
  font-weight: var(--kc-font-weight-label);
}

.kc-select__option [slot="description"] {
  color: var(--kc-color-text-muted);
  font-size: var(--kc-font-size-sm);
}

.kc-select__option[data-focused],
.kc-select__option[data-hovered] {
  background: var(--kc-color-accent-surface);
  color: var(--kc-color-accent-text);
}

.kc-select__option[data-selected] {
  box-shadow: inset 3px 0 0 var(--kc-color-accent-border);
}

.kc-select__option[data-disabled] {
  opacity: 0.5;
}

/* ---- Dialog -------------------------------------------------------------- */

/* A modal, and a drawer is the same object at a different placement.
 *
 * This treatment lives here rather than in `base.css` — which is where the
 * disclosure's went one component ago — and the difference between the two cases
 * is the whole of ADR 0002. A `<details>` works with no runtime, so its states
 * belong in the file every delivery mode loads. A `<dialog>` opens only when
 * something calls `showModal()`, so it is Mode 2 only, `renderStatic` throws on
 * it, and `static.css` has nothing to restore. It sits beside Select and Popover
 * because it is the same kind of thing they are.
 *
 * Nothing below is a pseudo-class, so the data-attribute-only rule this file
 * lives under is untouched: `[open]` is an attribute the browser writes, and
 * `::backdrop` is a pseudo-element. Neither is a state a hand-authored `.kc-`
 * page could fake into working.
 */

/* The UA hides a closed dialog with `display: none`, and an author `display`
   would beat it at any specificity — so the flex column is scoped to `[open]`
   rather than declared on the class. A `.kc-dialog` that is always visible is
   the failure this one selector prevents. */
.kc-dialog[open] {
  display: flex;
}

.kc-dialog {
  /* The Intrinsic Maximum Rule, in the form Popover already uses. Both consumer
     repos wrote a ceiling of their own — `min(100%, 600px)` and
     `min(42rem, calc(100vw - 2rem))` — so no caller constrains this from
     outside. The viewport term is what keeps the gutter at small sizes. */
  inline-size: min(42rem, calc(100vw - 2rem));
  /* Both maxima are restated rather than left to the UA, which caps a `dialog`
     at `calc(100% - 6px - 2em)` in each axis. That is a measure this component
     did not choose and cannot see: at 320 pixels it silently clamped the panel
     to 282 and the drawer to the same, so the Intrinsic Maximum Rule was being
     enforced by the browser rather than by the component. */
  max-inline-size: min(42rem, calc(100vw - 2rem));
  max-block-size: calc(100dvh - 2rem);
  flex-direction: column;
  /* Zero, because the head, body and footer own their own padding — that is what
     lets the body scroll while the other two hold still. Both of RD's dialogs
     reached the same conclusion. */
  padding: 0;
  border: 1px solid var(--kc-color-border);
  /* A dialog is a plate that has detached, so it takes the largest radius in the
     system rather than the keycap radius a popover wears. */
  border-radius: var(--kc-radius-plate);
  background: var(--kc-color-surface-raised);
  color: var(--kc-color-text);
  /* The Overlay Exception Rule: genuinely detached, so it casts in dark as well
     as light. AW's panel takes the plate shadow, which is `none` in dark, so its
     dialogs have no depth there at all. */
  box-shadow: var(--kc-shadow-overlay);
  /* Deliberately *not* `hidden`, which is what a rounded panel normally wants.
     A Select or a Popover inside this dialog is portalled into this element —
     see `overlay-portal.ts` — and clipping here would cut its menu off at the
     dialog's edge, which is the same failure in a new place. The body clips its
     own corner instead, below. */
  overflow: visible;
  font-family: var(--kc-font-body);
  animation: kc-popover-in var(--kc-duration-overlay) var(--kc-ease-overlay);
}

/* The scrim, and the token behind it is new — the token layer shipped none. Both
   consumer scrims are raw literals that fail the Phase 2 colour rule; what
   survives from them is the alpha, which the two repos picked independently and
   identically. See correction 30. */
.kc-dialog::backdrop {
  background: var(--kc-color-scrim);
  animation: kc-scrim-in var(--kc-duration-overlay) var(--kc-ease-overlay);
}

/* The drawer. RD's `.assumptions-drawer` is this same `<dialog>` pinned to the
   inline-end edge at full height, which is geometry rather than a component —
   `margin: 0 0 0 auto`, `height: 100%`, `width: min(560px, 100%)`. 560px is
   35rem. Stated logically so it flips for RTL, which RD's physical `margin-left`
   does not. */
.kc-dialog[data-placement="inline-end"],
.kc-dialog[data-placement="inline-start"] {
  inline-size: min(35rem, 100vw);
  max-inline-size: 100vw;
  block-size: 100dvh;
  max-block-size: 100dvh;
  margin-block: 0;
}

/* Flush against one viewport edge, so the corners on that edge are square and
   the border there would be a line drawn along the screen's own edge. */
.kc-dialog[data-placement="inline-end"] {
  margin-inline: auto 0;
  border-inline-end-width: 0;
  border-start-end-radius: 0;
  border-end-end-radius: 0;
}

.kc-dialog[data-placement="inline-start"] {
  margin-inline: 0 auto;
  border-inline-start-width: 0;
  border-start-start-radius: 0;
  border-end-start-radius: 0;
}

/* The head holds still. RD makes its head `position: sticky` because its whole
   dialog scrolls; here the body is the scroll container, so the head and footer
   are simply flex items that do not shrink. Same guarantee — the close control
   is reachable at every scroll offset — carried by layout rather than by an
   offset that has to be kept clear of the radius. AW scrolls the whole panel,
   header included, so its close control leaves the viewport in a long dialog. */
.kc-dialog__head {
  display: flex;
  flex: none;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--kc-space-4);
  padding: var(--kc-space-6);
  border-block-end: 1px solid var(--kc-color-divider);
}

.kc-dialog__heading {
  display: grid;
  gap: var(--kc-space-1);
}

/* The Title role, and the second place the display face appears inside a
   component. That follows from the same sentence that chose the radius: a dialog
   is a plate that has detached, and a plate's title is a card title. */
.kc-dialog__title {
  margin: 0;
  color: var(--kc-color-text);
  font-family: var(--kc-font-display);
  font-size: var(--kc-font-size-xl);
  font-weight: var(--kc-font-weight-title);
  line-height: var(--kc-line-height-heading);
}

.kc-dialog__description {
  margin: 0;
  color: var(--kc-color-text-muted);
  font-size: var(--kc-font-size-sm);
  line-height: var(--kc-line-height-label);
}

.kc-dialog__close {
  flex: none;
  /* The key keeps its 44px target while the visual gap stays step 6, the same
     trade the banner's dismiss makes. */
  margin: calc(var(--kc-space-2) * -1);
}

.kc-dialog__close svg {
  inline-size: 1.125rem;
  block-size: 1.125rem;
}

/* Step 5 between children, because what stacks in a dialog body is whole
   components — the same reasoning, and the same step, as a card body. */
.kc-dialog__body {
  display: grid;
  overflow: auto;
  align-content: start;
  gap: var(--kc-space-5);
  padding: var(--kc-space-6);
}

.kc-dialog__body > :first-child {
  margin-block-start: 0;
}

.kc-dialog__body > :last-child {
  margin-block-end: 0;
}

/* The Concentric Radius Rule with a gap of zero. The body is flush with the
   dialog's inner edge, so its corner is the parent's radius less nothing — and
   because the dialog itself may not clip, this is what stops scrolled content
   painting into the rounded corner. Only when the body reaches the bottom: with
   a footer below it, it has no corner there to round. */
.kc-dialog__body:last-child {
  border-end-start-radius: var(--kc-radius-plate);
  border-end-end-radius: var(--kc-radius-plate);
}

.kc-dialog__footer {
  display: flex;
  flex: none;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--kc-space-3);
  padding: var(--kc-space-6);
  border-block-start: 1px solid var(--kc-color-divider);
}

.kc-banner {
  display: flex;
  inline-size: min(100%, 48rem);
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--kc-space-3);
  padding: var(--kc-space-3) var(--kc-space-4);
  border: 1px solid var(--kc-color-info-border);
  border-inline-start-width: 4px;
  border-radius: var(--kc-radius-sm);
  background: var(--kc-color-info-surface);
  color: var(--kc-color-info-text);
  font-family: var(--kc-font-body);
}

.kc-banner[data-tone="success"] {
  border-color: var(--kc-color-success-border);
  background: var(--kc-color-success-surface);
  color: var(--kc-color-success-text);
}

.kc-banner[data-tone="warning"] {
  border-color: var(--kc-color-warning-border);
  background: var(--kc-color-warning-surface);
  color: var(--kc-color-warning-text);
}

.kc-banner[data-tone="danger"] {
  border-color: var(--kc-color-danger-border);
  background: var(--kc-color-danger-surface);
  color: var(--kc-color-danger-text);
}

.kc-banner__content {
  display: grid;
  gap: var(--kc-space-1);
}

.kc-banner__title {
  font-weight: var(--kc-font-weight-emphasis);
}

.kc-banner__body > :first-child {
  margin-block-start: 0;
}

.kc-banner__body > :last-child {
  margin-block-end: 0;
}

.kc-banner .kc-banner__dismiss {
  min-inline-size: var(--kc-control-min-size);
  min-block-size: var(--kc-control-min-size);
  flex: none;
  margin: calc(var(--kc-space-1) * -1);
  color: inherit;
}

.kc-banner__dismiss svg {
  inline-size: 1.125rem;
  block-size: 1.125rem;
}

.kc-badge {
  display: inline-flex;
  inline-size: fit-content;
  min-block-size: 1.5rem;
  align-items: center;
  gap: var(--kc-space-1);
  padding: var(--kc-space-1) calc(var(--kc-space-2) + 2px);
  border: 1px solid var(--kc-color-border);
  border-radius: var(--kc-radius-sm);
  background: var(--kc-color-surface-raised);
  color: var(--kc-color-text);
  font-family: var(--kc-font-body);
  font-size: var(--kc-font-size-xs);
  font-weight: var(--kc-font-weight-micro);
  line-height: var(--kc-line-height-micro);
}

.kc-badge[data-tone="info"] {
  border-color: var(--kc-color-info-border);
  background: var(--kc-color-info-surface);
  color: var(--kc-color-info-text);
}

.kc-badge[data-tone="success"] {
  border-color: var(--kc-color-success-border);
  background: var(--kc-color-success-surface);
  color: var(--kc-color-success-text);
}

.kc-badge[data-tone="warning"] {
  border-color: var(--kc-color-warning-border);
  background: var(--kc-color-warning-surface);
  color: var(--kc-color-warning-text);
}

.kc-badge[data-tone="danger"] {
  border-color: var(--kc-color-danger-border);
  background: var(--kc-color-danger-surface);
  color: var(--kc-color-danger-text);
}

/* The 999px radius `DESIGN.md` calls available and unused. It stays unused by
   default and is reached for only when the thing being labelled is genuinely in
   motion, where "floating token" is the correct connotation rather than an
   accident of taste. The extra inline padding is not decoration: at a full pill
   radius the horizontal padding a 6px corner needs leaves the first glyph
   sitting inside the curve. */
.kc-badge[data-shape="pill"] {
  padding-inline: var(--kc-space-3);
  border-radius: var(--kc-radius-pill);
}

/* The Tone Trio Rule's second carrier. Sized off the cap height rather than the
   box: at 0.75rem Micro type a 1rem glyph towers over its own label. */
.kc-badge__icon {
  inline-size: 0.875rem;
  block-size: 0.875rem;
  flex: none;
}

.kc-card {
  display: grid;
  inline-size: min(100%, 42rem);
  gap: var(--kc-space-5);
  padding: var(--kc-space-6);
  border: 1px solid var(--kc-color-divider);
  border-radius: var(--kc-radius-plate);
  background: var(--kc-color-surface-raised);
  color: var(--kc-color-text);
  box-shadow: var(--kc-shadow-plate);
  font-family: var(--kc-font-body);
}

.kc-card__header,
/* Step 5, because what stacks in a card body is whole components — two fields,
   a field and a banner — and the Layout section reserves steps 5 and 6 for
   composition between components while internal rhythm stays in 1–4. At step 2
   a field's own label sat exactly as far from its description as it did from
   the next field entirely, so proximity carried no information at all. */
.kc-card__body {
  display: grid;
  gap: var(--kc-space-5);
}

/* The one place the display face appears inside a component. At 1.25rem the
   face's optical size axis is doing real work, which is why nothing here pins
   it. */
.kc-card__title {
  margin: 0;
  color: var(--kc-color-text);
  font-family: var(--kc-font-display);
  font-size: var(--kc-font-size-xl);
  font-weight: var(--kc-font-weight-title);
  line-height: var(--kc-line-height-heading);
}

.kc-card__description {
  margin: 0;
  color: var(--kc-color-text-muted);
}

.kc-card__body > :first-child {
  margin-block-start: 0;
}

.kc-card__body > :last-child {
  margin-block-end: 0;
}

.kc-card__footer {
  display: flex;
  flex-wrap: wrap;
  gap: var(--kc-space-3);
  align-items: center;
  padding-block-start: var(--kc-space-4);
  border-block-start: 1px solid var(--kc-color-divider);
}

/* A card that navigates. It warms one step on hover rather than lifting: the
   plate shadow is `none` in dark, so a hover expressed as elevation would exist
   in one theme only. Surface tone works in both, which is the same reasoning
   the dark ladder is built on.
   No bottom edge and no travel — a card is the plate, and the plate does not
   depress. */
.kc-card[data-linked] {
  position: relative;
  color: var(--kc-color-text);
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--kc-duration-press) var(--kc-ease-press);
}

.kc-card[data-linked][data-hovered],
.kc-card[data-linked]:has(.kc-card__link[data-hovered]) {
  background: var(--kc-color-surface-hover);
}

.kc-card[data-linked][data-focus-visible],
.kc-card[data-linked]:has(.kc-card__link[data-focus-visible]) {
  outline: var(--kc-focus-ring);
  outline-offset: var(--kc-focus-ring-offset);
}

/* The accessible name is the title this wraps, not the whole card. The overlay
   is what makes the rest of the card clickable, and it is also why body text
   inside a linked card cannot be selected — stated in the component's docs
   rather than discovered. */
.kc-card__link {
  color: inherit;
  outline: none;
  text-decoration: none;
}

.kc-card__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

/* ---- Search field ------------------------------------------------------- */

/* The glyph and the clear key sit over the input rather than beside it in a
   wrapper, and that is a structural decision rather than a visual one. Keeping
   the border, fill, and focus ring on the input itself means this field reuses
   `.kc-field__input`'s existing `[data-hovered]` and `[data-focus-visible]`
   rules exactly. A wrapper carrying the box would have needed its own states,
   and the only way to write those without React Aria is `:focus-within` — a live
   interactive selector in the stylesheet that is supposed to have none. */
.kc-search-field__control {
  position: relative;
  display: flex;
  align-items: center;
  margin-block-start: calc(var(--kc-space-3) - var(--kc-space-1));
}

.kc-search-field__control .kc-field__input {
  margin-block-start: 0;
  padding-inline-start: calc(var(--kc-space-4) + 1.25rem + var(--kc-space-2));
  padding-inline-end: var(--kc-control-min-size);
}

.kc-search-field__icon {
  position: absolute;
  inset-inline-start: var(--kc-space-4);
  inline-size: 1.25rem;
  block-size: 1.25rem;
  color: var(--kc-color-text-muted);
  pointer-events: none;
}

/* `translate` rather than a transform, so the press transform the key inherits
   from `.kc-button` still composes with the centering instead of replacing it. */
.kc-search-field .kc-search-field__clear {
  position: absolute;
  inset-inline-end: 3px;
  inset-block-start: 50%;
  translate: 0 -50%;
  min-inline-size: var(--kc-control-min-size);
  min-block-size: var(--kc-control-min-size);
}

.kc-search-field__clear-glyph {
  inline-size: 1.125rem;
  block-size: 1.125rem;
}

/* ---- Description list --------------------------------------------------- */

/* Fifteen `<dl>` elements across the five consumer repos and five different
   implementations of them. Each pair is wrapped in a `div`, which HTML permits
   inside a `dl`, and that wrapper is what makes all three layouts one stylesheet
   rather than three: the pair becomes a box to lay out instead of two siblings
   to place by index.

   The doubled class on the inner selectors is the same guard `prose.css`
   documents: `.kc-prose dt` is (0,1,1) and a single `.kc-dl__term` is (0,1,0),
   so a description list dropped inside an article would silently revert to the
   article's rhythm. */
.kc-dl {
  display: grid;
  gap: var(--kc-space-3);
  margin: 0;
  color: var(--kc-color-text);
  font-family: var(--kc-font-body);
}

.kc-dl[data-layout="grid"] {
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: var(--kc-space-5) var(--kc-space-6);
}

.kc-dl .kc-dl__item {
  display: grid;
  gap: var(--kc-space-1);
  min-inline-size: 0;
}

.kc-dl[data-layout="rows"] .kc-dl__item {
  grid-template-columns: minmax(0, 11rem) minmax(0, 1fr);
  gap: var(--kc-space-1) var(--kc-space-4);
  align-items: baseline;
}

.kc-dl[data-divided] .kc-dl__item {
  padding-block-end: var(--kc-space-3);
  border-block-end: 1px solid var(--kc-color-divider);
}

.kc-dl[data-divided] .kc-dl__item:last-child {
  padding-block-end: 0;
  border-block-end: 0;
}

.kc-dl .kc-dl__term {
  margin: 0;
  color: var(--kc-color-text-muted);
  font-size: var(--kc-font-size-sm);
  font-weight: var(--kc-font-weight-label);
  line-height: var(--kc-line-height-label);
}

.kc-dl .kc-dl__details {
  margin: 0;
  min-inline-size: 0;
  color: var(--kc-color-text);
  overflow-wrap: break-word;
}

.kc-dl .kc-dl__details[data-numeric] {
  font-variant-numeric: tabular-nums;
  text-align: end;
}

/* ---- Empty state -------------------------------------------------------- */

/* A recess, not a raised object. It takes the page ground rather than the plate,
   because a card is a thing on the plate and reads as content, while an empty
   state is the shape content would fill. The border and the plate radius keep it
   an object rather than letting it dissolve into the page — which is the
   system's confirmed anti-reference. */
.kc-empty-state {
  display: grid;
  inline-size: min(100%, 42rem);
  justify-items: center;
  gap: var(--kc-space-3);
  padding: var(--kc-space-8) var(--kc-space-6);
  border: 1px solid var(--kc-color-divider);
  border-radius: var(--kc-radius-plate);
  background: var(--kc-color-surface);
  color: var(--kc-color-text);
  font-family: var(--kc-font-body);
  text-align: center;
}

.kc-empty-state__icon {
  display: inline-flex;
  inline-size: 2rem;
  block-size: 2rem;
  color: var(--kc-color-text-muted);
}

.kc-empty-state__icon > svg {
  inline-size: 100%;
  block-size: 100%;
}

/* The body face, not the display one. The Two Voice Rule puts Piazzolla in page
   headings and card titles; an empty state's heading is neither. */
.kc-empty-state__title {
  margin: 0;
  font-family: var(--kc-font-body);
  font-size: var(--kc-font-size-lg);
  font-weight: var(--kc-font-weight-title);
  line-height: var(--kc-line-height-heading);
}

.kc-empty-state__description {
  margin: 0;
  max-inline-size: 46ch;
  color: var(--kc-color-text-muted);
}

.kc-empty-state__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--kc-space-3);
  margin-block-start: var(--kc-space-2);
}

/* ---- Page header -------------------------------------------------------- */

/* The heading's own margins are zeroed and the header owns the rhythm instead.
   That follows the Heading Rhythm Rule rather than breaking it: a heading that
   opens its container has nothing above it to separate from, and the space that
   matters here belongs to the header as a block, not to the heading as a line.

   Sizes are declared here and nowhere else, for the reason the token package
   ships none — the surface decides how large a heading is, and a page header is
   a surface. */
.kc-page-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--kc-space-4) var(--kc-space-5);
  margin-block-end: var(--kc-space-6);
  color: var(--kc-color-text);
  font-family: var(--kc-font-body);
}

.kc-page-header[data-divided] {
  padding-block-end: var(--kc-space-4);
  border-block-end: 1px solid var(--kc-color-divider);
}

.kc-page-header__lead {
  display: grid;
  flex: 1 1 22rem;
  min-inline-size: 0;
  gap: 0;
}

.kc-page-header__eyebrow {
  margin: 0;
  color: var(--kc-color-text-muted);
  font-size: var(--kc-font-size-caps);
  font-weight: var(--kc-font-weight-micro);
  line-height: var(--kc-line-height-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.kc-page-header__title {
  margin: 0;
  max-inline-size: 24ch;
  font-family: var(--kc-font-display);
  font-weight: var(--kc-font-weight-display);
  line-height: var(--kc-line-height-heading);
  text-wrap: balance;
  overflow-wrap: break-word;
}

/* The eyebrow qualifies the title, so those two stay close. The description is
   the first body copy and needs a full composition step instead. Keeping the
   two relationships separate prevents a PageHeader rhythm fix from widening
   both, which is what one shared grid gap would do. */
.kc-page-header__eyebrow + .kc-page-header__title {
  margin-block-start: var(--kc-space-2);
}

h1.kc-page-header__title {
  font-size: clamp(1.7rem, 1.2rem + 1.7vw, 2.25rem);
}

h2.kc-page-header__title {
  font-size: clamp(1.4rem, 1.1rem + 1vw, 1.65rem);
}

h3.kc-page-header__title {
  font-size: var(--kc-font-size-xl);
}

.kc-page-header__description {
  margin: var(--kc-space-4) 0 0;
  max-inline-size: 58ch;
  color: var(--kc-color-text-muted);
}

.kc-page-header__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kc-space-3);
}

.kc-page-header__meta {
  display: flex;
  flex-basis: 100%;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kc-space-2);
}

/* ---- Code block --------------------------------------------------------- */

/* Deliberately the same treatment `prose.css` gives a `pre`, because a code
   sample in a product surface and one in an article are the same thing and the
   reader should not have to notice which page they are on.

   No focus rule appears here. The `pre` carries `tabindex="0"` because a
   scrollable region a keyboard cannot reach is a 2.1.1 failure, and `base.css`
   already rings every `:focus-visible` at zero specificity — so the focus
   indicator arrives from the tokens layer in every delivery mode, including
   markup this stylesheet never sees. */
.kc-code {
  display: grid;
  gap: var(--kc-space-2);
  color: var(--kc-color-text);
  font-family: var(--kc-font-body);
}

.kc-code__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kc-space-2);
}

.kc-code__label {
  color: var(--kc-color-text-muted);
  font-size: var(--kc-font-size-caps);
  font-weight: var(--kc-font-weight-micro);
  line-height: var(--kc-line-height-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* In the row above the block rather than floating over its corner: an overlaid
   control is always covering the first line, and one revealed on hover is
   invisible to touch and to the keyboard. Same decision `prose.css` records. */
.kc-code .kc-code__copy {
  margin-inline-start: auto;
}

.kc-code .kc-code__copy[data-copied] {
  border-color: var(--kc-color-success-border);
  background: var(--kc-color-success-surface);
  color: var(--kc-color-success-text);
}

.kc-code .kc-code__pre {
  margin: 0;
  padding: var(--kc-space-4) var(--kc-space-5);
  border: 1px solid var(--kc-color-divider);
  border-radius: var(--kc-radius-key);
  background: var(--kc-color-surface-raised);
  color: var(--kc-color-text);
  font-family: var(--kc-font-mono);
  font-size: var(--kc-font-size-code-block);
  line-height: var(--kc-line-height-body);
  white-space: pre;
  overflow-x: auto;
}

.kc-code .kc-code__pre[data-wrap] {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.kc-code .kc-code__pre code {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
}

.kc-code__token[data-token="comment"] {
  color: var(--kc-color-code-comment);
  font-style: italic;
}

.kc-code__token[data-token="punctuation"] {
  color: var(--kc-color-code-punctuation);
}

.kc-code__token[data-token="string"] {
  color: var(--kc-color-code-string);
}

/* Weight rather than a fifth hue. See the syntax tokens for why the palette
   stops at two colors here. */
.kc-code__token[data-token="keyword"] {
  color: var(--kc-color-code-keyword);
  font-weight: var(--kc-font-weight-emphasis);
}

/* ---- App shell ---------------------------------------------------------- */

/* All five consumer repos carry a bespoke shell and no two agree. This one is
   deliberately structural: apart from the nav link it contributes no interactive
   element of its own, so it needs almost nothing in `static.css` and composes
   with whatever router an app already has.

   The sidebar split uses flex wrapping rather than a second media query — the
   system is single-breakpoint, and a sidebar that reflows on its own content's
   terms is what the Intrinsic Maximum Rule asks for anyway. The sidebar
   separates itself by surface tone as well as by a rule, so it still reads as a
   distinct region once it has wrapped above the content. */
.kc-app-shell {
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-block-size: 100vh;
  min-block-size: 100dvh;
  background: var(--kc-color-surface);
  color: var(--kc-color-text);
  font-family: var(--kc-font-body);
}

.kc-app-shell__header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kc-space-3) var(--kc-space-5);
  min-block-size: 60px;
  padding: var(--kc-space-2) var(--kc-space-5);
  border-block-end: 1px solid var(--kc-color-divider);
  background: var(--kc-color-surface-raised);
}

/* Brand and navigation are the textual baseline group. Keep the bar itself
   centered so a marketing header with no navigation does not pull its wordmark
   to the block-start edge, and so unrelated action geometry cannot enlarge the
   group. */
.kc-app-shell__header:has(> .kc-app-shell__brand):has(> .kc-app-shell__nav)
  > :is(.kc-app-shell__brand, .kc-app-shell__nav) {
  align-self: baseline;
}

.kc-app-shell__header[data-sticky] {
  position: sticky;
  inset-block-start: 0;
  z-index: 20;
}

.kc-app-shell__brand {
  display: flex;
  align-items: baseline;
  gap: var(--kc-space-2);
  font-family: var(--kc-font-display);
  font-size: var(--kc-font-size-xl);
  font-weight: var(--kc-font-weight-title);
  line-height: var(--kc-line-height-heading);
}

/* A logo mark contributes size, not the wordmark's text baseline. */
.kc-app-shell__brand > :where(svg, img) {
  align-self: center;
}

.kc-app-shell__nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kc-space-1);
}

.kc-app-shell__nav-link {
  display: inline-flex;
  min-block-size: var(--kc-control-min-size);
  align-items: center;
  gap: var(--kc-space-2);
  padding-inline: var(--kc-space-3);
  border-radius: var(--kc-radius-key);
  color: var(--kc-color-text-muted);
  font-size: var(--kc-font-size-sm);
  font-weight: var(--kc-font-weight-label);
  text-decoration: none;
  cursor: pointer;
}

.kc-app-shell__nav-link[data-hovered] {
  background: var(--kc-color-surface-hover);
  color: var(--kc-color-text);
}

.kc-app-shell__nav-link[data-focus-visible] {
  outline: var(--kc-focus-ring);
  outline-offset: var(--kc-focus-ring-offset);
}

.kc-app-shell__nav-link[data-disabled] {
  opacity: 0.58;
  cursor: not-allowed;
}

/* The Select option's selection treatment, not the coral key. A sidebar is a
   list of options and navigating somewhere commits to nothing — the same call
   the documentation site's own chrome makes. */
.kc-app-shell__nav-link[aria-current="page"] {
  background: var(--kc-color-accent-surface);
  color: var(--kc-color-accent-text);
  box-shadow: inset 3px 0 0 var(--kc-color-accent-border);
}

.kc-app-shell__nav-group + .kc-app-shell__nav-group {
  margin-block-start: var(--kc-space-5);
  padding-block-start: var(--kc-space-4);
  border-block-start: 1px solid var(--kc-color-divider);
}

.kc-app-shell__nav-label {
  margin: 0 0 var(--kc-space-2);
  color: var(--kc-color-text-muted);
  font-size: var(--kc-font-size-caps);
  font-weight: var(--kc-font-weight-micro);
  line-height: var(--kc-line-height-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.kc-app-shell__nav-list {
  display: grid;
  gap: var(--kc-space-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.kc-app-shell__nav-list .kc-app-shell__nav-link {
  inline-size: 100%;
  justify-content: flex-start;
}

.kc-app-shell__nav-icon {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  inline-size: 1.125rem;
  block-size: 1.125rem;
}

.kc-app-shell__nav-icon > :where(svg, img) {
  inline-size: 100%;
  block-size: 100%;
}

.kc-app-shell__nav-meta {
  flex: none;
  margin-inline-start: auto;
  padding: 1px var(--kc-space-2);
  border: 1px solid var(--kc-color-divider);
  border-radius: var(--kc-radius-pill);
  background: var(--kc-color-surface);
  color: var(--kc-color-text-muted);
  font-size: var(--kc-font-size-xs);
  font-variant-numeric: tabular-nums;
  line-height: var(--kc-line-height-micro);
}

.kc-app-shell__nav-link[aria-current="page"] .kc-app-shell__nav-meta {
  border-color: var(--kc-color-accent-border);
  background: var(--kc-color-accent-surface);
  color: var(--kc-color-accent-text);
}

.kc-app-shell__nav-trigger {
  display: none;
}

.kc-app-shell__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kc-space-2);
  margin-inline-start: auto;
}

.kc-app-shell__body {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  min-inline-size: 0;
}

.kc-app-shell__body[data-sidebar-layout] {
  display: grid;
  grid-template-columns: clamp(13rem, 16vw, 14rem) minmax(0, 1fr);
  align-items: stretch;
}

.kc-app-shell__sidebar {
  flex: 1 1 14rem;
  min-inline-size: 0;
  padding: var(--kc-space-5);
  border-inline-end: 1px solid var(--kc-color-divider);
  background: var(--kc-color-surface-raised);
}

.kc-app-shell__sidebar[data-density="compact"] .kc-app-shell__nav-link {
  min-block-size: 36px;
}

.kc-app-shell__sidebar[data-sticky] {
  position: sticky;
  inset-block-start: 0;
  align-self: start;
  max-block-size: 100dvh;
  overflow-y: auto;
}

.kc-app-shell__body[data-sidebar-layout] .kc-app-shell__main {
  max-inline-size: none;
  margin-inline: 0;
}

/* The grow factor is what makes the split behave without a query: the content
   takes essentially all the free space while both are on one row, and drops the
   sidebar to its own row the moment 30rem of content no longer fits beside it. */
.kc-app-shell__main {
  --kc-app-shell-measure: 72rem;

  flex: 999 1 30rem;
  min-inline-size: 0;
  max-inline-size: var(--kc-app-shell-measure);
  margin-inline: auto;
  padding: var(--kc-space-6) var(--kc-space-5) var(--kc-space-10);
}

.kc-app-shell__footer {
  padding: var(--kc-space-5);
  border-block-start: 1px solid var(--kc-color-divider);
  color: var(--kc-color-text-muted);
  font-size: var(--kc-font-size-sm);
}

@media (max-width: 52rem) {
  .kc-app-shell__body[data-sidebar-layout] {
    display: block;
  }

  .kc-app-shell__body[data-sidebar-layout] > .kc-app-shell__sidebar[data-collapsible] {
    display: none;
  }

  .kc-app-shell__nav-trigger {
    display: inline-flex;
  }
}

/* ---- Data table --------------------------------------------------------- */

/* Every declaration below is `prose.css`'s table treatment, and that is the
   point rather than an accident: a table of numbers in a dashboard and a table
   of numbers in an article are the same object. Shipping a second, nearly-equal
   look is how `retirement-dashboard` ended up with eight table classes, four of
   them copies, one of which silently lost a `text-align` on the way. A unit test
   compares the two files rather than trusting this comment.

   One consequence worth naming: because the two treatments are identical, a
   `.kc-table` dropped inside a `.kc-prose` article needs no specificity guard.
   `.kc-dl` doubles its class to beat `.kc-prose dt`; there is nothing to beat
   here, whichever stylesheet loads second.

   Nothing in this section is a pseudo-class, and there is no `static.css`
   counterpart, because the component has no interactive state at all — see the
   component's doc comment for why a row hover would cost Mode 1. The scroll
   container's focus ring comes from `base.css` in every delivery mode. */
.kc-table-scroll {
  overflow-x: auto;
  scrollbar-gutter: stable;
}

.kc-table {
  inline-size: 100%;
  border-collapse: collapse;
  color: var(--kc-color-text);
  font-family: var(--kc-font-body);
  font-size: var(--kc-font-size-sm);
}

.kc-table caption {
  padding-block-end: var(--kc-space-2);
  color: var(--kc-color-text-muted);
  font-size: var(--kc-font-size-sm);
  font-weight: var(--kc-font-weight-label);
  text-align: start;
  caption-side: top;
}

/* A raised surface with a weighted rule beneath it, not a band of brand color.
   Coral marks a commitment and a table header commits to nothing; the raised
   tone is the device a Card already uses to sit above the plate, and it inverts
   correctly in dark without a second declaration. */
.kc-table thead th {
  padding: var(--kc-space-3) var(--kc-space-4);
  border-block-end: 2px solid var(--kc-color-border);
  background: var(--kc-color-surface-raised);
  color: var(--kc-color-text);
  font-weight: var(--kc-font-weight-label);
  text-align: start;
  vertical-align: bottom;
}

.kc-table tbody td,
.kc-table tbody th {
  padding: var(--kc-space-3) var(--kc-space-4);
  border-block-end: 1px solid var(--kc-color-divider);
  vertical-align: top;
}

.kc-table tbody th {
  color: var(--kc-color-text);
  font-weight: var(--kc-font-weight-label);
  text-align: start;
}

.kc-table tbody tr:last-child > * {
  border-block-end: 0;
}

/* Opt-in. The row rules already separate the rows, and a second separator on top
   of the first is noise on a table short enough to scan. */
.kc-table[data-zebra] tbody tr:nth-child(even) {
  background: var(--kc-color-surface-hover);
}

/* `text-align: start` rather than the UA's centered `th`. A totals row reads as
   a continuation of the column above it, and a centered label in a table of
   start-aligned ones is the kind of thing nobody names but everybody sees. */
.kc-table tfoot th,
.kc-table tfoot td {
  padding: var(--kc-space-3) var(--kc-space-4);
  border-block-start: 2px solid var(--kc-color-border);
  background: var(--kc-color-surface-raised);
  font-weight: var(--kc-font-weight-label);
  text-align: start;
}

/* Figures compare by digit position, so they align on their end edge and take
   lining, fixed-width numerals. `nowrap` because a figure broken across two
   lines is a figure that gets misread — the reason `retirement-dashboard` sets
   it on its own numeric cells. */
.kc-table [data-numeric] {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-align: end;
}

@keyframes kc-popover-in {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
}

/* The scrim fades on its own timing rather than inheriting the panel's, because
   `::backdrop` is a sibling box rather than a parent. Same duration, so the two
   arrive together, and the same token — so reduced motion takes both to 0ms
   from the tokens layer with no branch here. */
@keyframes kc-scrim-in {
  from {
    opacity: 0;
  }
}

@media (max-width: 30rem) {
  .kc-card {
    padding: var(--kc-space-5);
  }

  .kc-banner {
    padding-inline: var(--kc-space-3);
  }

  .kc-empty-state {
    padding: var(--kc-space-6) var(--kc-space-5);
  }

  .kc-dialog__head,
  .kc-dialog__body,
  .kc-dialog__footer {
    padding: var(--kc-space-5);
  }

  .kc-code .kc-code__pre {
    padding-inline: var(--kc-space-4);
  }

  /* Below the measure a term and its value have no room to sit side by side, so
     the pair stacks and proximity carries the grouping instead. */
  .kc-dl[data-layout="rows"] .kc-dl__item {
    grid-template-columns: minmax(0, 1fr);
  }

  .kc-app-shell__header,
  .kc-app-shell__main,
  .kc-app-shell__sidebar,
  .kc-app-shell__footer {
    padding-inline: var(--kc-space-4);
  }
}

/* Reduced motion is not handled here. Travel, edge compression, chevron turn,
   durations, and the pressed key face are all tokens, so the tokens package
   owns the whole substitution — see `--kc-press-*` in tokens.css. */

@media (forced-colors: active) {
  .kc-button,
  .kc-field__input,
  .kc-select__trigger,
  .kc-popover,
  .kc-select__popover,
  .kc-dialog,
  .kc-banner,
  .kc-badge,
  .kc-card,
  .kc-empty-state,
  .kc-code .kc-code__pre {
    border-color: ButtonText;
  }

  /* An inline link has no box to outline, so its underline is the whole
     affordance and it must survive the color being taken away. */
  .kc-button[data-variant="link"] {
    border-color: transparent;
    text-decoration-thickness: 2px;
  }

  /* The status shape is the tone's second carrier, so it has to keep its paint
     when the OS flattens everything else. Losing it is exactly the failure this
     mode exists to prevent. */
  .kc-badge__icon {
    forced-color-adjust: none;
    color: CanvasText;
  }

  .kc-app-shell__header,
  .kc-app-shell__sidebar,
  .kc-app-shell__footer,
  .kc-page-header[data-divided],
  .kc-dl[data-divided] .kc-dl__item,
  .kc-dialog__head,
  .kc-dialog__footer {
    border-color: ButtonText;
  }

  /* The header and totals bands are carried by a background the OS flattens, so
     the rule that separates them from the body has to survive on its own. Same
     treatment `prose.css` gives an article's table. */
  .kc-table thead th,
  .kc-table tfoot th,
  .kc-table tfoot td {
    border-color: ButtonText;
  }

  .kc-table[data-zebra] tbody tr:nth-child(even) {
    background: none;
  }

  .kc-app-shell__nav-link[aria-current="page"] {
    color: HighlightText;
    background: Highlight;
    box-shadow: none;
  }

  .kc-button[data-focus-visible],
  .kc-field__input[data-focus-visible],
  .kc-select__trigger[data-focus-visible],
  .kc-app-shell__nav-link[data-focus-visible],
  .kc-card[data-linked][data-focus-visible],
  .kc-card[data-linked]:has(.kc-card__link[data-focus-visible]),
  .kc-select__option[data-focused] {
    outline: 3px solid Highlight;
    outline-offset: 2px;
  }

  .kc-select__option[data-selected] {
    color: HighlightText;
    background: Highlight;
    box-shadow: none;
  }

  .kc-button[data-disabled],
  .kc-app-shell__nav-link[data-disabled],
  .kc-select__option[data-disabled] {
    color: GrayText;
    opacity: 1;
  }
}

/* The only print rules in this file, and they are corrections rather than
   polish. A scroll container prints what fits and silently loses the rest, which
   is data loss the component itself introduced; a header that does not repeat
   leaves every page after the first unlabelled; and a row split across a page
   break is a row nobody can read. `retirement-dashboard` reached all three
   conclusions independently and regression-tests them, which is what a
   dashboard people print looks like. */
@media print {
  .kc-table-scroll {
    overflow: visible;
  }

  .kc-table thead {
    display: table-header-group;
  }

  .kc-table tr {
    break-inside: avoid;
  }
}

/* The skip link's landmark contributes no box of its own. Its child is clipped
   at rest and fixed-position when focused, so a wrapper with any layout would
   reserve space for something that is never in the flow. */
.kc-app-shell__skip {
  display: contents;
}
