/* kit.css - the control kit. One sheet, one prefix, one answer per control.
   ============================================================================
   WHY THIS FILE EXISTS. An audit of the admin wing on 2026-09-16 counted twenty
   three controls across five stylesheets wearing SEVEN heights (24, 28, 32, 36,
   40, 44 and "whatever the padding came to"), NINE font sizes from 11px to 15px,
   TWO families - six controls were set in the mono face that this theme reserves
   for data, labels and badges - THREE radii for one shape, and TWO focus offsets.
   Nothing was broken. Everything was slightly different from everything else,
   which is what "it looks raw" means when someone says it and cannot point at a
   bug.
   This sheet is the whole answer: three heights, two sizes, one family, one
   radius (plus the pill a tab wants), one focus rule. Every number is a token in
   tokens.css, and a fourth height means editing that file where a reader can see
   it rather than adding a rule here.

   LINKED, NOT INJECTED. The admin bar rides on every page of the reading surface,
   so the kit cannot be a string a view injects on first render the way
   views/registry/styles.mjs and views/desk/styles.mjs do. It is a <link> in
   src/app/index.html, after shell.css so it can lean on the global :focus-visible
   rule there rather than restating it.

   FOCUS IS NOT RESTATED HERE, DELIBERATELY. shell.css carries
   `:focus-visible{outline:2px solid var(--accent);outline-offset:2px}` and it
   reaches every control in this sheet. Three view sheets each carried their own
   copy at offset:1px, which is how one application came to have two focus rings.
   Adding a third copy here would have been the fourth.

   MOTION. Only transform and opacity move, every duration is a --dur-* token, and
   the two easings are used in the pairing tokens.css states: the CLOSED rule
   carries --ease-exit and the open rule re-declares the same transition with
   --ease. checks/check-motion.mjs reads this file.                            */

/* ── buttons ─────────────────────────────────────────────────────────────── */
/* The base carries geometry and type and NO colour: a button with no variant is a
   mistake that should look like one rather than quietly inheriting the primary. */
.k-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;block-size:var(--h-ctl);padding-inline:14px;font-family:var(--font-ui);font-size:var(--fs-ctl);font-weight:500;line-height:1;border:1px solid transparent;border-radius:var(--r-md);background:none;color:var(--body);text-decoration:none;white-space:nowrap;cursor:pointer;-webkit-appearance:none;appearance:none}
/* An icon is sized in em so it tracks the label it sits beside, and never
   vertical-align:middle - the flex line box already centres it. */
.k-btn svg{inline-size:1.25em;block-size:1.25em;flex:none}
.k-btn:active{transform:translateY(.5px)}

/* EXACTLY ONE PER PAGE. Filled where everything else is outlined, and that is the
   whole of its dominance: it does not also grow, move or pulse. */
.k-btn--primary{background:var(--accent);border-color:var(--accent);color:#fff;box-shadow:var(--sh)}
.k-btn--primary:hover{background:var(--accent-ink);border-color:var(--accent-ink);box-shadow:var(--sh-raise)}
[data-mode="dark"] .k-btn--primary{color:var(--paper)}
/* The reading canvas paints every link the accent (shell.css .docbody a), which
   outranks a class and drew a primary anchor's label in the button's own colour -
   an empty blue box, found on the uat rung. */
.docbody a.k-btn--primary{color:#fff}
[data-mode="dark"] .docbody a.k-btn--primary{color:var(--paper)}

.k-btn--secondary{background:var(--card);border-color:var(--rule);color:var(--body)}
.k-btn--secondary:hover{border-color:var(--rule2);color:var(--text)}

.k-btn--ghost{background:none;border-color:transparent;color:var(--soft)}
.k-btn--ghost:hover{background:var(--wash);color:var(--accent)}

/* Destructive, and it says what it destroys: the label names its object ("Retire
   this draft"), and it goes last in a row so the hand does not land on it first. */
.k-btn--danger{background:var(--danger-wash);border-color:color-mix(in srgb,var(--danger) 35%,transparent);color:var(--danger)}
.k-btn--danger:hover{border-color:var(--danger)}

/* Square. It carries no label, so it MUST carry aria-label - there is nothing else
   for a screen reader to read. */
.k-btn--icon{inline-size:var(--h-ctl);padding-inline:0}
.k-btn--icon svg{inline-size:18px;block-size:18px}
/* The dense variant: a table row action, a pager, a tab, the batch bar. Combine
   with --icon for a 32x32 square. */
.k-btn--sm{block-size:var(--h-ctl-sm);padding-inline:10px;font-size:var(--fs-ctl-sm)}
.k-btn--sm.k-btn--icon{inline-size:var(--h-ctl-sm);padding-inline:0}
.k-btn--sm.k-btn--icon svg{inline-size:16px;block-size:16px}
/* The tall variant, for a control standing alone in a form rather than in a row. */
.k-btn--lg{block-size:var(--h-ctl-lg);padding-inline:16px}

/* aria-disabled, not [disabled]: the control stays focusable, so a keyboard reader
   can reach it and be told why it is refused rather than tabbing past a hole. */
.k-btn[aria-disabled="true"]{opacity:.5;cursor:not-allowed}
.k-btn[aria-disabled="true"]:hover{background:inherit;border-color:inherit;color:inherit;box-shadow:none}
/* Busy. The caller captures the rest width into min-inline-size before swapping the
   label, so the row does not reflow around a spinner. */
.k-btn[aria-busy="true"]{cursor:progress}
.k-btn[aria-busy="true"] .k-spin{display:inline-block}
.k-spin{display:none;inline-size:16px;block-size:16px;border:2px solid currentColor;border-top-color:transparent;border-radius:var(--r-circle);animation:k-spin var(--dur-slow) linear infinite}
@keyframes k-spin{to{transform:rotate(360deg)}}
/* The blanket reduced-motion rule shortens a duration; an infinite loop needs its
   own answer, because a 0.01ms period is a strobe rather than a stillness. */
@media (prefers-reduced-motion:reduce){.k-spin{animation:none;border-top-color:currentColor;opacity:.5}}

/* ── inputs ──────────────────────────────────────────────────────────────── */
.k-input,.k-select{block-size:var(--h-ctl);padding-inline:12px;font-family:var(--font-ui);font-size:var(--fs-ctl);font-weight:400;color:var(--text);background:var(--card);border:1px solid var(--rule);border-radius:var(--r-md);min-inline-size:0}
.k-select{padding-inline-end:28px;cursor:pointer}
.k-input:hover,.k-select:hover{border-color:var(--rule2)}
.k-input::placeholder{color:var(--muted)}
.k-input[readonly]{background:var(--wash);color:var(--soft)}
/* 16px below the phone boundary. Mobile Safari zooms the viewport on focus for
   anything smaller, and the zoom is not undone when the field blurs. */
@media (max-width:768px){.k-input,.k-select{font-size:16px}}

/* A label above its control at 8px, and fields 16px apart. Both from the spacing
   step this theme already uses; neither is a number chosen here. */
.k-field{display:flex;flex-direction:column;gap:8px}
.k-field+.k-field{margin-block-start:16px}
.k-field>label{font-family:var(--font-ui);font-size:var(--fs-ctl-sm);font-weight:500;color:var(--body)}
.k-hint{font-family:var(--font-ui);font-size:var(--fs-ctl-sm);color:var(--soft);margin:0}
.k-hint.is-error{color:var(--danger)}

/* A checkbox aligned to the text beside it, not to the line box: 18px is the box
   the platform draws at this font size, and the 1px nudge lands its centre on the
   cap height rather than the baseline. */
.k-check{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-ui);font-size:var(--fs-ctl);color:var(--body);cursor:pointer}
.k-check input{inline-size:18px;block-size:18px;margin:0;flex:none;accent-color:var(--accent);cursor:pointer}

/* ── tabs ────────────────────────────────────────────────────────────────── */
/* Real links in a real nav, so the address is the state and a middle click opens
   one in a tab. aria-current="page" is the selected one, and the only one. */
.k-tabs{display:flex;flex-wrap:wrap;gap:4px}
.k-tab{display:inline-flex;align-items:center;gap:6px;block-size:var(--h-ctl-sm);padding-inline:12px;font-family:var(--font-ui);font-size:var(--fs-ctl-sm);font-weight:500;color:var(--body);text-decoration:none;border:1px solid var(--rule);border-radius:var(--r-pill);white-space:nowrap}
.k-tab:hover{border-color:var(--rule2);color:var(--text)}
.k-tab[aria-current="page"]{background:var(--wash);border-color:var(--accent);color:var(--accent-ink)}
/* The one place mono survives: a count is data. */
.k-count{font-family:var(--font-mono);font-size:11px;font-variant-numeric:tabular-nums;color:var(--muted)}
.k-tab[aria-current="page"] .k-count{color:var(--accent-ink)}

/* ── notices ─────────────────────────────────────────────────────────────── */
/* One region under the page head, never a toast: a toast takes the consequence of
   an act away from the place the act happened, and times out while the reader is
   still deciding. The colour is on the inline-start edge, 2px, so the notice reads
   as a note in the margin rather than a coloured slab. */
.k-notice{display:flex;align-items:flex-start;gap:10px;padding:10px 14px;margin-block-end:12px;font-family:var(--font-ui);font-size:var(--fs-ctl-sm);line-height:1.5;color:var(--body);background:var(--wash);border:1px solid var(--rule);border-inline-start:2px solid var(--accent);border-radius:var(--r-md)}
.k-notice--warn{background:var(--danger-wash);border-inline-start-color:var(--danger)}
.k-notice__icon{inline-size:16px;block-size:16px;flex:none;margin-block-start:2px;color:var(--accent)}
.k-notice--warn .k-notice__icon{color:var(--danger)}
.k-notice__text{flex:1;min-inline-size:0}
.k-notice__undo{flex:none}
.k-notice__dismiss{flex:none}

/* ── the drawer ──────────────────────────────────────────────────────────── */
/* A right panel the list stays live under: it is a place to LOOK at one row's
   history, not a modal decision, so nothing behind it is disabled. Escape closes
   it and focus returns to whatever opened it - both are the opener's job, not this
   sheet's. */
.k-drawer{position:fixed;inset-block:var(--h-header) 0;inset-inline-end:0;inline-size:min(320px,92vw);z-index:96;background:var(--paper);border-inline-start:1px solid var(--rule2);box-shadow:var(--sh-pop);overflow-y:auto;transform:translateX(103%);visibility:hidden;transition:transform var(--dur-med) var(--ease-exit),visibility 0s linear var(--dur-med)}
.k-drawer[data-open="true"]{transform:none;visibility:visible;transition:transform var(--dur-med) var(--ease),visibility 0s linear 0s}

/* ── the menu ────────────────────────────────────────────────────────────── */
/* A popover list of real buttons and real links - the account menu, and a row's
   overflow once three actions is too many to keep inline. */
.k-menu{min-inline-size:200px;padding:6px;background:var(--card);border:1px solid var(--rule2);border-radius:var(--r-xl);box-shadow:var(--sh-pop);z-index:97}
.k-menu__item{display:flex;align-items:center;gap:10px;inline-size:100%;block-size:var(--h-ctl-sm);padding-inline:10px;font-family:var(--font-ui);font-size:var(--fs-ctl-sm);font-weight:500;color:var(--body);text-align:start;text-decoration:none;background:none;border:0;border-radius:var(--r-md);cursor:pointer}
.k-menu__item:hover{background:var(--wash);color:var(--text)}
.k-menu__item .k-count{margin-inline-start:auto}

/* ADMIN PAGES SPEAK IN THE UI FACE. The reading face belongs to documents, and the one
   document in the wing is the draft on the Desk's canvas (#edmount), which keeps it.
   Before this rule a form's description was set in the serif and its hint in the sans,
   two faces inside one field. One page-head scale too: every admin h1 is the display
   face at 24px/500, and a section heading never outweighs the page's own. */
html[data-admin] .docbody :is(p,li,dd,dt,label,figcaption):not(#edmount *){font-family:var(--font-ui)}
html[data-admin] .docbody :is(.setpage,.deskpage) p:not(#edmount *){font-size:14px;line-height:1.6}
html[data-admin] .docbody h1:not(#edmount *){font-family:var(--font-display);font-size:24px;font-weight:500;line-height:1.2;letter-spacing:0}
html[data-admin] .docbody :is(h2,h3):not(#edmount *){font-family:var(--font-display);font-weight:500;letter-spacing:0}
html[data-admin] .docbody h2:not(#edmount *){font-size:18px;line-height:1.3}
html[data-admin] .docbody h3:not(#edmount *){font-size:15px;line-height:1.35}
html[data-admin] .docbody a.k-btn{text-decoration:none}

/* The drawer opens BELOW the top bar, not over it: a panel about one row of the table has
   no business covering the way out of the wing. Its head is one row - the title takes the
   room and clips, Close keeps its size. */
.k-drawer{padding:16px}
.k-drawer__head{display:flex;align-items:flex-start;gap:12px;margin-block-end:12px}
.k-drawer__head h2{flex:1 1 auto;min-inline-size:0;margin:0;padding:0;border:0;font:500 16px/1.3 var(--font-display);overflow-wrap:anywhere}
.k-drawer__head .k-btn{flex:none}
html[data-admin] .docbody .k-drawer__head h2{font-size:16px}

/* ── the media tile, its grid, and an upload's own row ────────────────────── */
/* Three classes, added 2026-09-17 with the media library (V12). They replace the
   six `.gal-*` rules that lived in views/desk/styles-stage.mjs, where a card was
   170x110 for every image whatever its shape and its only text was 10.5px mono.
   Card padding is 12/14 rather than the 24/32 a content card takes: a 280px
   thumbnail tile with two lines of metadata is the dense case, and the grid gap
   of 16 already exceeds the largest inner gap. The FILENAME IS --font-ui at 13px
   (--fs-ctl-sm); mono survives on the numbers only, which is the sheet's rule
   everywhere else. */
.k-card-grid{display:grid;gap:16px;
  grid-template-columns:repeat(auto-fill,minmax(min(100%,280px),1fr))}

.k-media-card{position:relative;display:flex;flex-direction:column;min-inline-size:0;
  background:var(--card);border:1px solid var(--rule);border-radius:var(--r-md);
  overflow:hidden;transition:border-color var(--dur-micro) var(--ease)}
.k-media-card:hover{border-color:var(--rule2)}
.k-media-card[aria-selected="true"]{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
/* A square box with the image covering it: the tile is a uniform grid and the TRUE
   ratio is shown in the drawer, at size, where the judgement is actually made. The
   width and height attributes stay on the img so the box is reserved before the
   bytes arrive. */
/* block-size:auto is LOAD-BEARING, not tidiness. The width and height ATTRIBUTES stay
   on the img so the box is reserved before the bytes arrive, and a specified height on
   one axis and a specified width on the other means aspect-ratio is ignored outright:
   measured 2026-09-17, a 1600x500 tile painted 283 by 500 with `aspect-ratio: 1 / 1`
   computing correctly and doing nothing. */
.k-media-card__shot{aspect-ratio:1/1;inline-size:100%;block-size:auto;object-fit:cover;
  background:var(--wash);display:block}
.k-media-card__body{padding:12px 14px;display:grid;gap:4px}
.k-media-card__name{font:500 var(--fs-ctl-sm)/1.35 var(--font-ui);color:var(--text);
  overflow-wrap:anywhere}
.k-media-card__meta{font:400 11px/1.4 var(--font-mono);font-variant-numeric:tabular-nums;
  color:var(--soft)}

/* One row per file being uploaded, and it stays readable until it is dismissed.
   Three files used to produce one note that overwrote itself twice. */
.k-progress-row{display:grid;grid-template-columns:32px 1fr max-content;gap:10px;
  align-items:center;padding:8px 0;border-block-end:1px solid var(--rule);
  font:400 var(--fs-ctl-sm)/1.4 var(--font-ui)}
.k-progress-row__bar{block-size:4px;border-radius:var(--r-pill);background:var(--wash2);overflow:hidden}
/* THE FILL MOVES ON transform, NOT ON inline-size. The brief wrote this line as a
   width transition; checks/check-motion.mjs refuses one, and correctly - a width
   transition forces layout on every frame on every engine. scaleX from a left
   origin paints identically and stays on the compositor. */
.k-progress-row__bar>i{display:block;block-size:100%;inline-size:100%;border-radius:inherit;
  background:var(--accent);transform-origin:left center;transform:scaleX(0);
  transition:transform var(--dur-small) var(--ease)}
/* Two tiles across on a phone. The 280px track the grid asks for gives one tile at 390px
   wide, a tile taller than the screen; two tracks of 165px hold a name and a meta line. */
@media (max-width:640px){.k-card-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
