/* KioskMDM UI - a small, self-contained design system.
   Light by default, dark via prefers-color-scheme. No external assets.

   The page is a tinted ground and the content sits on white surfaces laid
   on it: a section, a strip of facts, a table, the activity feed. The tint
   is what makes a surface read as one thing rather than as a run of
   paragraphs, so a page is a handful of objects instead of a wall of text
   divided by hairlines.

   Inside a surface the hairlines still do the dividing - a row of settings
   is not eight nested boxes - and status is still coloured words rather
   than a pill, because a pill draws a border round one word to make it
   look important and the word was already there. */

:root {
  --bg: #f5f6fa;
  --surface: #ffffff;
  --surface-2: #eef1f8;
  --surface-3: #e7eaf2;
  --text: #1a1f36;
  --muted: #6b7392;
  --faint: #9aa2c0;
  --border: #e2e6f0;
  --border-strong: #d2d7e6;
  --accent: #4666ff;
  --accent-ink: #2f45cc;
  --accent-soft: #eaeeff;
  --danger: #e5484d;
  --danger-ink: #c22a2f;
  --danger-line: #f2ccce;
  --danger-soft: #fdecec;
  --danger-wash: #fdf7f7;
  --ok: #1a9d63;
  --ok-soft: #e6f6ee;
  --warn: #b7791f;
  --warn-ink: #7d5310;
  --warn-line: #eddfbe;
  --warn-soft: #fbf1dc;
  --shadow: 0 1px 2px rgba(20, 26, 54, .06), 0 4px 16px rgba(20, 26, 54, .05);
  --radius: 10px;
  --radius-sm: 8px;
  /* One height for everything that stands in a row of controls. A select
     renders its own line box taller than an input's and a button's is
     shorter, so three controls sharing a padding still came out 38, 36 and
     34px and sat on three different baselines. */
  --control-h: 38px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0d1017;
    --surface: #161a26;
    --surface-2: #1f2434;
    --surface-3: #262c45;
    --text: #e9ecf6;
    --muted: #9aa2c0;
    --faint: #767e9d;
    --border: #262b3f;
    --border-strong: #363d61;
    --accent: #6a86ff;
    --accent-ink: #93a7ff;
    --accent-soft: #1c2340;
    --danger: #ff6169;
    --danger-ink: #ff8b91;
    --danger-line: #4a2429;
    --danger-soft: #2d1a20;
    --danger-wash: #1c151a;
    --ok: #35c98a;
    --ok-soft: #12271f;
    --warn: #eab55a;
    --warn-ink: #eac68a;
    --warn-line: #3c331d;
    --warn-soft: #241f13;
    --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 8px 24px rgba(0, 0, 0, .25);
  }
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font: 15px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  /* A word longer than the column it is in - an enrolment URL, a bundle id,
     an email address - breaks rather than pushing the page sideways. Only
     words that would otherwise overflow are touched, so ordinary prose wraps
     exactly as before. Without it the enrolment page scrolled horizontally on
     every phone, because the token URL is one 60-character word. */
  overflow-wrap: break-word;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-ink); }

h1 { font-size: 26px; font-weight: 700; letter-spacing: -.02em; margin: 0 0 4px; }
h2 { font-size: 15px; font-weight: 650; margin: 26px 0 10px; }
.section-title { margin: 28px 0 4px; }
.section-title + .muted { margin-top: 0; }
h3 { font-size: 15px; font-weight: 650; margin: 0 0 6px; }
p { margin: 8px 0; }
.muted { color: var(--muted); font-size: 13px; }
.lead { color: var(--muted); font-size: 14px; margin-top: 5px; }

/* Body copy gets a measure. A paragraph the width of a 936px panel is about
   137 characters a line, roughly twice what anybody reads comfortably; the
   panel keeps its width, because the tables and the forms in it use it. In
   `ch` rather than pixels so the 13px asides and the 15px prose each get the
   same number of characters rather than the same number of pixels.

   A paragraph or list item that *holds* a control is a row of controls that
   happens to be marked up as one, so it is left alone - capping it would
   squeeze the controls instead of the words. */
main p:not(:has(input, select, textarea, button, .btn, form)),
main li:not(:has(input, select, textarea, button, .btn, form)),
main dd:not(:has(input, select, textarea, button, .btn, form)) {
  max-width: 78ch;
}
/* The strips of facts are label-and-value pairs in narrow cells, not prose. */
.fact-groups dd, .cfgpairs dd, table.grid p { max-width: none; }

code {
  background: var(--surface-2); padding: 2px 6px; border-radius: 6px;
  font: 12.5px/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: var(--text); word-break: break-all;
}

/* ---- Top bar ---------------------------------------------------------- */

.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 6px;
  padding: 0 24px; min-height: 58px;
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  backdrop-filter: saturate(1.4) blur(8px);
  border-bottom: 1px solid var(--border);
}
/* The padding and the negative margin that cancels it give the brand a box to
   highlight without moving the logo a pixel: the border box starts 8px to the
   left of where it did and the content starts exactly where it did. It was the
   only thing in the bar that answered a pointer with nothing - `:hover` set
   the colour it already had, to stop the generic `a:hover` turning the
   wordmark blue, and stopped there. */
.brand {
  display: flex; align-items: center; gap: 9px;
  font-weight: 750; font-size: 16px; letter-spacing: -.01em; color: var(--text);
  padding: 6px 8px; margin: 0 2px 0 -8px; border-radius: 8px;
}
.brand:hover { color: var(--text); }
.brand .logo {
  width: 26px; height: 26px; border-radius: 7px;
  background: linear-gradient(135deg, var(--accent), #8a5bff);
  display: grid; place-items: center; color: #fff; flex: none;
}
.topbar nav { display: flex; gap: 2px; align-items: center; }
.topbar nav a {
  color: var(--muted); font-weight: 550; font-size: 14px;
  padding: 7px 12px; border-radius: 8px; line-height: 1;
}
.topbar nav a:hover { color: var(--text); background: var(--surface-2); }
.topbar nav a.active { color: var(--accent-ink); background: var(--accent-soft); }
.topbar .spacer { margin-left: auto; }
/* The signed-out end of the bar: a plain way in, and the registration the
   sign-up policy actually allows. Sits where the user menu does when there
   is somebody to show one for. */
.topbar-auth { display: flex; align-items: center; gap: 4px; flex: none; }
.topbar-auth a:not(.btn) {
  color: var(--muted); font-weight: 550; font-size: 14px;
  padding: 7px 12px; border-radius: 8px; line-height: 1;
}
.topbar-auth a:not(.btn):hover { color: var(--text); background: var(--surface-2); }
.navburger {
  display: none; place-items: center; flex: none;
  width: 38px; height: 38px; border-radius: var(--radius-sm);
  color: var(--muted); cursor: pointer;
  /* It is a <label>, so it was picking up the 12px block margin that form
     labels get, making it 62px inside a 58px bar. */
  margin: 0 0 0 4px;
}
.navburger:hover { background: var(--surface-2); color: var(--text); }
.navburger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.usermenu { position: relative; flex: none; }
.usermenu-trigger {
  display: flex; align-items: center; gap: 10px;
  background: none; border: 0; padding: 5px 6px; margin: 0;
  border-radius: var(--radius-sm); cursor: pointer; font: inherit; color: inherit;
  width: auto; height: auto;
}
.usermenu-trigger:hover, .usermenu.here .usermenu-trigger { background: var(--surface-2); }
.usermenu-trigger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.usermenu .who { display: flex; flex-direction: column; line-height: 1.2; text-align: right; }
.usermenu .who .name { font-size: 13px; font-weight: 600; }
.usermenu .who .role { font-size: 11px; color: var(--muted); }

/* The account and the server live here rather than in the bar: the bar is for
   the fleet. Hover opens it; focus does too, so it works from the keyboard
   and from a tap, neither of which hovers. */
.usermenu-panel {
  display: none; position: absolute; top: 100%; right: 0; z-index: 30;
  min-width: 220px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
.usermenu:hover .usermenu-panel,
.usermenu:focus-within .usermenu-panel { display: block; }
.usermenu-head {
  display: flex; flex-direction: column; gap: 1px;
  padding: 8px 10px 10px; margin-bottom: 4px;
  border-bottom: 1px solid var(--border);
}
.usermenu-head strong { font-size: 13.5px; font-weight: 650; }
.usermenu-head span { font-size: 12px; color: var(--muted); word-break: break-all; }
.usermenu-panel a {
  display: block; padding: 8px 10px; border-radius: var(--radius-sm);
  font-size: 14px; font-weight: 550; color: var(--text);
}
.usermenu-panel a:hover { background: var(--surface-2); color: var(--text); }
.usermenu-panel a.active { color: var(--accent-ink); background: var(--accent-soft); }
/* The operator's own pages are a group inside the menu, not a second menu:
   one more level to open would be one more thing to find. */
.usermenu-group {
  padding: 10px 10px 4px; margin-top: 4px; border-top: 1px solid var(--border);
  font-size: 11px; font-weight: 650; letter-spacing: .04em;
  text-transform: uppercase; color: var(--faint);
}
.usermenu-out {
  margin-top: 4px; padding-top: 8px !important;
  border-top: 1px solid var(--border); border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  color: var(--muted) !important;
}
.avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  background: linear-gradient(135deg, var(--accent), #8a5bff);
  color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 700;
}

/* ---- Layout ----------------------------------------------------------- */

main { max-width: 1000px; margin: 0 auto; padding: 24px 32px 72px; }
.page-head { margin-bottom: 16px; }
.row-between { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.back { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; color: var(--muted); margin-bottom: 10px; }
.back:hover { color: var(--accent); }

/* The aside under a form - what the control just above will do, what we
   cannot do for you, where to go instead. It was set inline on twenty
   paragraphs at five different margins; it is one distance. */
.note { color: var(--muted); font-size: 13px; margin: 12px 0 0; }
/* Holds a line open for a message that is usually not there, so the panel
   does not jump when one arrives - without leaving a paragraph's margin
   below the control while it is empty. */
.field-status { color: var(--muted); font-size: 13px; margin: 8px 0 0; min-height: 1.2em; }
.note:first-child { margin-top: 0; }
/* A single field in a row of them should not stretch to the panel's width. */
.field-narrow { max-width: 340px; }

/* ---- Surfaces --------------------------------------------------------- */
/* Every surface insets its content by 22px, so the left edge of the text is
   the same all the way down a page whichever kind of panel it is in. It was
   18px on a facts strip, 20px on a table and on the activity feed and 22px on
   a section, which put three different left edges on the device page alone. */
/* One rule makes a white panel on the tinted page. Everything that is a
   thing on a page - a section, a facts strip, a table, the activity feed -
   uses it, so they line up and cast the same shadow instead of each
   arriving at its own idea of a box. */

.surface, .section, .card, .facts, .cards, .events, .empty,
.table-panel, .fact-panel, main > .disclose, .danger-zone {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  margin: 0 0 16px;
}

/* The workhorse: what the setting is on the left, the controls on the
   right. `.card` is the same panel under its old name, so pages that have
   not been rewritten get the surface without being touched. */

.section, .card {
  display: flex; gap: 32px;
  padding: 20px 22px;
}
.section.tight { padding: 16px 22px; }
.section > .side { width: 190px; flex: none; }
.section > .side h3, .section > .side h2 { margin: 0; }
.section > .side p { margin: 4px 0 0; color: var(--muted); font-size: 13px; }
.section > .body { flex: 1; min-width: 0; }
.card { display: block; }
.card > h2:first-child, .card > h3:first-child, .section > .body > h3:first-child { margin-top: 0; }
.card hr.rule { border: 0; border-top: 1px solid var(--border); margin: 18px 0; }

/* The sign-in, sign-up and enrolment boxes are one panel on an otherwise
   empty page, so they are narrow and stand off the top bar rather than
   sitting under it. Every one of these pages used to set its own width and
   its own `margin: 0 auto`, which cancelled the standoff each time. Whether
   the text inside is centred is a separate question, so it is a separate
   class: a form full of labels wants `solo`, a PIN wants both. */
.card.solo { max-width: 460px; margin: 8vh auto; padding: 32px; }
.card.center { text-align: center; }

/* ---- Facts strip ------------------------------------------------------ */
/* Five numbers about a device, read across in one line rather than as five
   floating tiles competing for the same attention.

   The dividing hairlines are the grid's own 1px gaps with the border colour
   showing through, not a border on each cell. That way a strip that wraps
   to a second row divides correctly at every wrap, instead of the cell that
   happens to start a new row carrying a stray rule down its left. */

.facts, .cards {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  overflow: hidden;
}
/* Each cell draws its own left and top hairline just outside itself, and the
   panel's `overflow: hidden` clips the ones that would land on its border -
   the leftmost column's and the top row's. A strip that wraps therefore
   divides correctly at every wrap, where a border-left on each cell put a
   stray rule down whichever cell happened to start a new row. Drawn per cell
   rather than as 1px grid gaps over a coloured container, because the empty
   tracks left by a short last row would show that colour through. */
.fact, .stat-card {
  min-width: 0;
  box-shadow: -1px 0 0 var(--border), 0 -1px 0 var(--border);
}
.fact { padding: 13px 22px; }
/* A second row of facts under the first reads as a continuation, not as a
   rival headline, so it is quieter. */
.facts.subtle .fact-v { font-size: 14px; font-weight: 600; }
.fact-k {
  font-size: 11.5px; font-weight: 650; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted);
}
.fact-v {
  font-size: 15px; font-weight: 600; margin-top: 3px;
  display: flex; align-items: center; gap: 6px; min-width: 0;
}
.fact-v.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 14px; }
.fact-v.warn { color: var(--warn); }
.fact-v.unknown { color: var(--faint); font-weight: 500; }

/* The dashboard's fleet counters share the facts strip's grid. */
.stat-card { padding: 16px 22px; }
.stat-num { font-size: 22px; font-weight: 700; letter-spacing: -.02em; }
.stat-label { color: var(--muted); font-size: 12.5px; margin-top: 2px; }

/* ---- Tabs ------------------------------------------------------------- */

/* The rail under the tabs is painted as a 1px strip of background rather
   than a border on the container, so the active tab's underline can sit on
   it without being pulled down over it.

   It used to be a border, with each tab pulled down a pixel by
   `margin-bottom: -1px` to cover it. That one pixel of overflow was enough to
   raise a scrollbar: `overflow-x: auto` computes the other axis to `auto`
   too, so the strip scrolled vertically over a pixel it could not show. */
.tabs {
  display: flex; gap: 2px; margin: 4px 0 16px;
  overflow-x: auto; overflow-y: hidden;
  background: linear-gradient(var(--border), var(--border)) bottom left / 100% 1px no-repeat;
}
.tabs a {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 11px 14px; white-space: nowrap;
  font-size: 14px; font-weight: 600; color: var(--muted);
  border-bottom: 2px solid transparent;
}
.tabs a:hover { color: var(--text); }
.tabs a.active { color: var(--text); border-bottom-color: var(--accent); }
.tabs .count { font-weight: 500; color: var(--faint); }

/* ---- Status words ----------------------------------------------------- */
/* Was a pill. A pill puts a border and a fill around one word to make it
   look important; the word was already there. */

.badge {
  display: inline; font-size: 13px; font-weight: 600;
  color: var(--muted); padding: 0; border: 0; background: none;
  /* A status is one word however many words it is spelled with: "Locked to
     one app" broken across two lines reads as two facts. */
  white-space: nowrap;
}
.badge .dot { display: none; }
.badge.on { color: var(--ok); }
.badge.off { color: var(--muted); font-weight: 500; }
.badge.warn { color: var(--warn); }
.badge.accent { color: var(--accent-ink); }
.badge.danger { color: var(--danger); }

/* ---- Battery ---------------------------------------------------------- */

.battery { display: inline-flex; align-items: center; gap: 8px; min-width: 110px; width: 100%; max-width: 170px; }
.battery .track {
  display: block; flex: 1; min-width: 48px; height: 8px; border-radius: 999px;
  background: var(--surface-3); overflow: hidden;
}
.battery .fill { display: block; height: 100%; border-radius: 999px; background: var(--ok); }
.battery .fill.low { background: var(--warn); }
.battery .fill.crit { background: var(--danger); }
.battery .pct { font-size: 13px; font-variant-numeric: tabular-nums; color: var(--muted); min-width: 34px; }

/* ---- Tables ----------------------------------------------------------- */

/* A table that is a page's content is a surface of its own; one inside a
   section is already on one, so it only needs to scroll.

   The inset comes from the cells, not from padding on the panel. Padding the
   panel made every row narrower than the panel, so the row highlight was a
   square-cornered grey band floating inside the rounded card with a margin
   all round it. Cell padding puts the text in the same place and lets the
   row - and its highlight - run the full width, where the panel's own
   overflow rounds it off at the first and last row. */
.table-wrap { overflow-x: auto; }
.section .table-wrap, .card .table-wrap { margin-top: 16px; }
.table-panel > table.grid > thead > tr > th { padding-top: 16px; }
.table-panel > table.grid > thead > tr > th:first-child,
.table-panel > table.grid > tbody > tr > td:first-child { padding-left: 22px; }
.table-panel > table.grid > thead > tr > th:last-child,
.table-panel > table.grid > tbody > tr > td:last-child { padding-right: 22px; }
.table-panel > table.grid > tbody > tr:last-child > td { padding-bottom: 16px; }
table.grid { width: 100%; border-collapse: collapse; }
table.grid th {
  text-align: left; padding: 0 14px 11px 0; font-size: 11.5px; font-weight: 650;
  text-transform: uppercase; letter-spacing: .04em; color: var(--muted);
  white-space: nowrap;
}
table.grid td { padding: 12px 14px 12px 0; border-top: 1px solid var(--border); vertical-align: middle; }
table.grid tbody tr.linked { cursor: pointer; }
table.grid td .primary-cell { font-weight: 600; }
table.grid td.right, table.grid th.right { text-align: right; padding-right: 0; }
.cell-sub { color: var(--muted); font-size: 12.5px; }
.fleet-count { margin: 0 0 8px; color: var(--muted); font-size: 13px; }

/* The managed app configuration editor. A key column that shrinks to fit its
   content puts base_url on two lines, so the three columns are given fixed
   proportions and the inputs fill them. */
table.grid.cfg-table { table-layout: fixed; }
.cfg-table col, .cfg-table th:nth-child(1) { width: 34%; }
.cfg-table th:nth-child(2) { width: 130px; }
.cfg-table th:nth-child(4) { width: 90px; }
.cfg-table td { padding-right: 10px; }
.cfg-table input, .cfg-table select { width: 100%; margin: 0; }
.cfg-table input { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; }

/* The descent: one block per layer beneath the one being edited, in the order
   they apply. The rule down the left is what makes it read as a stack rather
   than as a list of unrelated tables. */
.cfglayers { border-left: 2px solid var(--border); padding-left: 14px; margin: 0 0 16px; }
.cfglayer + .cfglayer { margin-top: 12px; }
.cfglayer-head {
  font-size: 11.5px; font-weight: 650; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted); margin-bottom: 5px;
}
.cfgpairs { margin: 0; }
.cfgpairs > div { display: flex; gap: 12px; padding: 3px 0; align-items: baseline; }
.cfgpairs dt { flex: 0 0 190px; margin: 0; }
.cfgpairs dd {
  margin: 0; min-width: 0; font-size: 13px; word-break: break-word;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
/* Beaten by a layer above: still shown, because "the app sets this and the
   group replaces it" is the thing somebody came to the page to find out. */
.cfgpairs > div.beaten dd { text-decoration: line-through; color: var(--muted); }
.cfgpairs > div.beaten dt code { color: var(--muted); }
.cfgpairs .from {
  text-decoration: none; display: inline-block; margin-left: 8px;
  font-family: inherit; font-size: 12px; color: var(--muted);
}
.cfgresult { margin-top: 16px; }
.cfgsuggest { margin-top: 18px; border-top: 1px solid var(--border); padding-top: 14px; }
/* The button carries a key name as long as a bundle id, so it cannot be
   `flex: none`: it took its whole content width and left the description a
   column one word wide, and under 430px it pushed the page sideways. It wraps
   its own label now, and the description drops to a line of its own as soon as
   there is not room for both. */
.cfgsuggest li { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: baseline; padding: 7px 0; }
.cfgsuggest li > .btn {
  flex: 0 1 auto; min-width: 0; max-width: 100%;
  white-space: normal; text-align: left;
}
.cfgsuggest li > .btn code { word-break: break-all; }
.cfgsuggest li > .muted { flex: 1 1 200px; min-width: 0; }
.cfgsuggest em { font-style: normal; color: var(--faint); }

/* ---- Buttons ---------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  padding: 9px 15px; cursor: pointer; font-size: 14px; font-weight: 600;
  line-height: 1; white-space: nowrap; transition: background .12s, border-color .12s;
  /* .btn is worn by <a>, <button> and <label>. Without this a label wearing
     it picks up the block margin that form labels get. */
  margin: 0;
}
.btn:hover { background: var(--surface-2); border-color: var(--muted); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn.primary:hover { background: var(--accent-ink); border-color: var(--accent-ink); }
.btn.danger { background: var(--surface); border-color: var(--border-strong); color: var(--danger); }
.btn.danger:hover { background: var(--danger-soft); border-color: var(--danger); }
.btn.danger.solid { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn.danger.solid:hover { background: var(--danger-ink); border-color: var(--danger-ink); }
.btn.ghost { background: transparent; border-color: transparent; color: var(--muted); }
.btn.ghost:hover { background: var(--surface-2); color: var(--text); }
.btn.small { padding: 6px 11px; font-size: 12.5px; }
.btn { min-height: var(--control-h); }
.btn.small { min-height: 0; }
.btn:disabled { opacity: .4; cursor: not-allowed; }
.btn.block { width: 100%; }

/* ---- Forms ------------------------------------------------------------ */

label { display: block; margin: 12px 0; font-size: 13px; font-weight: 600; color: var(--text); }
label .hint { display: block; font-weight: 400; color: var(--muted); font-size: 12px; margin-top: 2px; }
input, select, textarea {
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  padding: 9px 11px; font-size: 14px; font-family: inherit; width: 100%; margin-top: 6px;
}
/* A textarea grows with its rows, and a checkbox, radio or file input is not
   a field of this shape - everything else is one line and one height. */
input:not([type=checkbox]):not([type=radio]):not([type=file]), select {
  height: var(--control-h);
}
input::placeholder { color: var(--faint); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
input[type=file] { padding: 8px; background: var(--surface-2); }
/* A tick box is not a field of that shape: it has its own size, whatever the
   label around it is called. It was inheriting the `width: 100%` above, so a
   checkbox in a label that had not been given `.check` stretched the width of
   the panel and stood 13px tall in the middle of it. 18px is also something
   a thumb can hit, where the browser default 13px is not. */
input[type=checkbox], input[type=radio] {
  width: 18px; height: 18px; margin: 0; flex: none; accent-color: var(--accent);
}
/* A row of fields with its button on the end. Applies to a bare .inline div
   too, not only a form: a form that needs a confirm dialog wraps the row. */
.inline { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; margin: 0; }
/* 150px is the basis at which a field plus its neighbours plus the button on
   the end still fit the 670px a section's body gets, so the button stays on
   the row instead of being orphaned under it. Fields grow past it to fill
   whatever room there is; the basis only decides when the row wraps. */
.inline label { margin: 0; flex: 1 1 150px; }
/* A field in a row of them that should not grow with the others - a duration,
   a store country. It was an inline `flex: 0 0 190px` on the two forms that
   have one, which no breakpoint could then reach. */
.inline label.f-short { flex: 0 0 190px; }
/* And one that wants room for a sentence or an address but not the whole
   panel: a "reason" box 815px wide is a box sized by the space around it
   rather than by what goes in it. */
.inline label.f-wide { flex: 0 1 320px; }
.inline .btn { margin-bottom: 1px; }
/* The same row inside a table cell, where a select and its Save button are
   the whole form and there is no label above them to line up with. */
.inline.tight { gap: 6px; align-items: center; }
/* Beside the label, not under it - a hint on one field in a row otherwise
   pushes that field down while its neighbours stay put. */
.inline label .hint { display: inline; margin: 0 0 0 5px; }
.field-row { display: flex; gap: 12px; flex-wrap: wrap; }
.field-row label { flex: 1 1 160px; }
.narrow { max-width: 340px; }
/* The padding is what a hover has to paint; the negative margin keeps the
   words where they were without it. It is a bigger target as well - the whole
   label has always been clickable, and now it looks it. */
label.check {
  display: flex; align-items: flex-start; gap: 9px; font-weight: 500;
  padding: 5px 8px; margin: 5px -8px; border-radius: var(--radius-sm);
}
/* The box lines up with the first line of the label rather than with the
   middle of a label that wrapped to three lines. 2px is the offset between
   an 18px box and a 15px line box. */
label.check input { margin-top: 2px; }
label.check .hint { display: inline; margin: 0; }
.check-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 2px 32px; }

/* A checkbox and its button on one line, at the right-hand end of a list row:
   the choice sits with the button that acts on it, not in a dialog after. */
.row-form { display: flex; align-items: center; gap: 14px; margin: 0; }
.row-form label.check { margin: 0 -8px 0 0; font-size: 13px; color: var(--muted); }
ul.plain { list-style: none; padding: 0; margin: 0; }
ul.plain li { padding: 6px 0; border-top: 1px solid var(--border); }
ul.plain li:first-child { border-top: 0; }

.actionbar { display: flex; gap: 8px; flex-wrap: wrap; }
.actionbar form { margin: 0; }

/* ---- Disclosure ------------------------------------------------------- */

main > .disclose, .fact-panel { padding: 16px 22px; }
.disclose > summary {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  font-size: 14px; font-weight: 600; color: var(--accent); list-style: none;
  /* A summary that carries an aside as well as a title - "Google Chrome",
     "nothing set here" - is two flex items, so without this the aside kept a
     column of its own and squeezed the title into one word a line. */
  flex-wrap: wrap;
}
.disclose > summary::-webkit-details-marker { display: none; }
.disclose > summary::before {
  content: ""; width: 0; height: 0; flex: none;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  transition: transform .15s;
}
.disclose[open] > summary::before { transform: rotate(90deg); }
.disclose.danger > summary { color: var(--danger); font-size: 15px; font-weight: 650; }

/* ---- The end of a device ---------------------------------------------- */

.danger-zone { margin-top: 18px; border: 1px solid var(--danger-line); border-radius: var(--radius); }
.danger-step {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 20px; padding: 18px 22px; border-top: 1px solid var(--danger-line);
}
.danger-step:first-child { border-top: 0; }
/* The words absorb the slack and the controls keep their natural width. They
   were both free to size themselves, so the form was squeezed until its
   button wrapped under its own input - on the same page where the step below
   it kept input and button on one line. */
.danger-step > :first-child { flex: 1 1 auto; min-width: 0; }
.danger-step > form, .danger-step > .inline, .danger-step > .actionbar { flex: none; }
/* A wrapping flex container is only as wide as its widest item, so a form
   allowed to wrap here reported the width of its input and then wrapped its
   own button underneath it. The action row is one row. */
.danger-step > form.inline { flex-wrap: nowrap; }
.danger-step h4 { margin: 0; font-size: 14.5px; font-weight: 600; }
.danger-step p { margin: 3px 0 0; color: var(--muted); font-size: 13px; max-width: 620px; }
.danger-step.worst {
  display: block; background: var(--danger-wash);
  border-radius: 0 0 calc(var(--radius) - 1px) calc(var(--radius) - 1px);
}
.danger-step.worst h4 { color: var(--danger-ink); }

/* ---- Activity --------------------------------------------------------- */

.events { margin-top: 14px; padding: 6px 22px 10px; }
.event {
  display: flex; align-items: baseline; gap: 12px;
  padding: 10px 0; border-top: 1px solid var(--border); font-size: 14px;
}
.event:first-child { border-top: 0; }
.event .what { flex: 1; min-width: 0; }
.event .outcome { font-size: 13px; font-weight: 600; }
.event .outcome.ok { color: var(--ok); }
.event .outcome.bad { color: var(--danger); }
.event .outcome.waiting { color: var(--warn); }
.event .when { font-size: 13px; color: var(--muted); width: 130px; text-align: right; flex: none; }
.event .why { display: block; font-size: 12.5px; color: var(--muted); margin-top: 2px; }

/* ---- Notices ---------------------------------------------------------- */

.flashes { display: flex; flex-direction: column; gap: 8px; margin: 16px 0; }
/* A notice is a paragraph, and becomes a row only when something sits beside
   the words - a warning icon, or a button that belongs on the right. It was a
   row always, and a flex row makes a flex item of every child: a message of
   "text, <a>link</a>, ." was laid out as three columns, the link in the
   middle one and the full stop stranded at the far right. */
.flash, .notice {
  display: block;
  padding: 11px 14px; border-radius: var(--radius-sm); font-size: 13.5px; line-height: 1.5;
  border: 1px solid var(--border); background: var(--surface);
  box-shadow: var(--shadow);
  animation: flash-in .2s ease;
}
.flash svg, .notice svg { flex: none; margin-top: 2px; }
.flash-ok { background: var(--ok-soft); border-color: color-mix(in srgb, var(--ok) 35%, transparent); color: var(--ok); }
.flash-warn, .notice.warn { background: var(--warn-soft); border-color: var(--warn-line); color: var(--warn-ink); }
.flash-danger { background: var(--danger-soft); border-color: color-mix(in srgb, var(--danger) 35%, transparent); color: var(--danger); }
.flash-message, .flash-info { color: var(--text); }
.flash code, .notice code { background: color-mix(in srgb, currentColor 12%, transparent); color: inherit; }
.notice a { color: inherit; text-decoration: underline; }
.flash:has(svg), .notice:has(svg), .notice:has(form) {
  display: flex; align-items: flex-start; gap: 10px;
}
@keyframes flash-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

/* ---- Empty states ----------------------------------------------------- */

.empty { padding: 26px 22px; color: var(--muted); }
.empty .emoji { display: none; }
.empty h3 { color: var(--text); margin-bottom: 4px; }

/* ---- Wizard steps ----------------------------------------------------- */

.steps { list-style: none; counter-reset: step; padding: 0; margin: 8px 0 0; }
.steps > li {
  position: relative; padding: 0 0 22px 44px; counter-increment: step;
  border-left: 2px solid var(--border); margin-left: 14px;
  /* The prose in a step is a bare text node beside a form, so the measure
     rule cannot reach it and the step carries the cap instead. Nothing else
     in one is wider than a button. */
  max-width: 78ch;
}
.steps > li:last-child { border-left-color: transparent; padding-bottom: 0; }
.steps > li::before {
  content: counter(step); position: absolute; left: -15px; top: -2px;
  width: 28px; height: 28px; border-radius: 50%; background: var(--accent);
  color: #fff; display: grid; place-items: center; font-size: 13px; font-weight: 700;
  box-shadow: 0 0 0 4px var(--surface);
}
/* The step's own title, not every `strong` inside the step. As a descendant
   selector this caught an emphasised word in a nested paragraph and made a
   block of it, so "Use Renew on the existing certificate" was printed as
   three lines with one word on the middle one. */
.steps > li > strong { display: block; margin-bottom: 4px; }
.steps form { margin-top: 8px; }

/* ---- Misc ------------------------------------------------------------- */

.qr {
  width: 240px; height: 240px; max-width: 100%; border-radius: var(--radius);
  background: #fff; padding: 10px; border: 1px solid var(--border);
}
.result-plist { margin: 6px 0 0; }
.result-plist summary { cursor: pointer; color: var(--accent); font-size: 12.5px; }
.result-plist pre { background: var(--surface-2); padding: 10px; border-radius: 6px; overflow: auto; font-size: 12px; max-height: 260px; }
.divider { height: 1px; background: var(--border); margin: 20px 0; border: 0; }
.pill-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.dl { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 18px 32px; }
.dl dt { font-size: 13px; color: var(--muted); }
.dl dd { margin: 2px 0 0; font-size: 14.5px; font-weight: 600; }
.found {
  display: flex; align-items: center; gap: 14px; margin-top: 16px;
  padding: 14px 16px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-2);
}
.found img { width: 46px; height: 46px; border-radius: 11px; flex: none; background: var(--surface-3); }
.found .who { flex: 1; min-width: 0; }
.found .who b { font-size: 15px; font-weight: 650; }
.found .who span { display: block; font-size: 13px; color: var(--muted); margin-top: 1px; }
.foot { text-align: center; color: var(--muted); padding: 24px; font-size: 12.5px; border-top: 1px solid var(--border); }

/* ---- The long tail of what a device says about itself ----------------- */
/* Printed in full rather than folded behind a disclosure: it is what the page
   is for, and a click to see it is a click every time. Several columns, so
   forty answers are not one long ribbon nobody reaches the end of. */

/* Row gap carries the space between stacked groups, so the heading itself has
   no top margin and every group on the top row starts level with the panel. */
.fact-groups {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 16px 40px;
}
.fact-group h4 {
  margin: 0 0 4px; font-size: 11.5px; font-weight: 650;
  letter-spacing: .04em; text-transform: uppercase; color: var(--muted);
}
.fact-group dl { margin: 0; }
.fact-group dl > div {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; padding: 7px 0; border-top: 1px solid var(--border);
}
.fact-group dt { font-size: 13px; color: var(--muted); flex: none; }
.fact-group dd {
  margin: 0; font-size: 13px; text-align: right;
  word-break: break-all; min-width: 0;
}

/* ---- The group tree --------------------------------------------------- */
/* Indentation carries the nesting. A tick before a child's name marks it as
   one, so the shape survives a row wrapping on a narrow screen. */

.tree-row { display: inline-flex; align-items: center; gap: 8px; }
.tree-tick {
  width: 10px; height: 10px; flex: none; margin-right: 2px;
  border-left: 1px solid var(--border-strong);
  border-bottom: 1px solid var(--border-strong);
  border-bottom-left-radius: 3px;
}

/* ---- Inherit / allow / block ------------------------------------------ */
/* Three radios that read as one control. The middle state is silence, which
   is what makes a child able to override one setting and leave the rest. */

.tri { display: inline-flex; border: 1px solid var(--border-strong); border-radius: 8px; overflow: hidden; flex: none; }
.tri input { position: absolute; opacity: 0; pointer-events: none; width: 0; }
.tri label {
  margin: 0; padding: 6px 11px; font-size: 12.5px; font-weight: 600;
  color: var(--muted); cursor: pointer; background: var(--surface);
  border-left: 1px solid var(--border-strong); line-height: 1.2;
}
.tri label:first-of-type { border-left: 0; }
.tri input:checked + label { background: var(--surface-3); color: var(--text); }
.tri input:checked + label.allow { background: var(--ok-soft); color: var(--ok); }
.tri input:checked + label.block { background: var(--danger-soft); color: var(--danger); }
.tri input:focus-visible + label { outline: 2px solid var(--accent); outline-offset: -2px; }

.setting {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 10px 0; border-top: 1px solid var(--border);
}
.setting .what { min-width: 0; }
.setting .what strong { font-weight: 500; font-size: 14px; }
.setting .from { display: block; font-size: 12px; color: var(--muted); margin-top: 1px; }

/* ---- Where a value came from ----------------------------------------- */

.inherited { font-size: 12.5px; color: var(--muted); }
.crumb { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 13px; color: var(--muted); }
.crumb .sep { color: var(--faint); }

/* ---- Support access banner -------------------------------------------- */
/* A support session shows the customer's own pages, so without this nothing
   on screen says whose account it is or that a clock is running on it. It
   sits above the content, full width, and does not scroll away with it. */

.acting-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  flex-wrap: wrap; padding: 10px 22px; font-size: 13.5px; line-height: 1.5;
  background: var(--warn-soft); border-bottom: 1px solid var(--warn-line);
  color: var(--warn-ink);
}
.acting-bar strong { font-weight: 700; }
.acting-clock { display: inline-block; margin-left: 4px; font-variant-numeric: tabular-nums; opacity: .85; }
.acting-actions { display: flex; gap: 8px; }
/* Access held but stepped out of. Quieter than the amber bar: nothing is
   being done as the customer at this moment, and a page that shouts the same
   way in both states stops being read in either. */
.acting-bar.held {
  background: var(--accent-soft); border-bottom-color: var(--border-strong);
  color: var(--text);
}

/* Collapse the nav into a toggle menu before the links can overflow the bar.
   The open menu is an absolutely-positioned dropdown panel (the sticky topbar
   is its containing block) so it overlays the page rather than stretching the
   bar. Pure CSS (checkbox hack) - no JS, htmx-friendly.

   The width it has to collapse at is simply the width of the links. It used
   to vary with who was signed in - an admin carried five more - and one
   breakpoint at 860px was below what either needed, so the nav wrapped to a
   second row inside a bar with a fixed 58px height and the second row was
   clipped by it. Everything account- and server-shaped now lives under the
   name in the corner, so the bar is the same six links for everybody and one
   breakpoint fits. `min-height` keeps a bar that does wrap from hiding the
   overflow.

   Adding a nav link means re-measuring: sum the rendered link widths plus the
   brand and the user menu, and put the breakpoint above it. */
.topbar nav a { white-space: nowrap; }


@media (max-width: 960px) {
  .navburger { display: grid; }
  .topbar nav {
    display: none;
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 2px;
    padding: 6px 14px 12px;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow);
  }
  #navtoggle:checked ~ nav { display: flex; }
  .topbar nav a { padding: 11px 12px; font-size: 15px; }
}

/* The two-column section folds to one at the width where 220px of label
   beside a form field stops being readable. */
@media (max-width: 720px) {
  .section { flex-direction: column; gap: 14px; }
  .section > .side { width: auto; }
}

/* ---- Hover ------------------------------------------------------------ */
/* The states a pointer gets, gathered rather than scattered, because what was
   scattered had gaps: the three-state restriction control, every tick-box
   label, every disclosure and every link inside a notice said `cursor:
   pointer` and then did nothing when the pointer arrived.

   Behind `hover: hover` because a touch screen has no hover to leave: iOS
   applies these on tap and leaves them applied until something else is
   tapped, so on an iPad an untreated rule reads as "this row is selected"
   long after the tap that caused it. The buttons and the nav keep their own
   unguarded rules - a button that stays lit for a moment after a tap looks
   like a button that was pressed, which it was. A whole row does not. */

@media (hover: hover) {
  /* Inherit / allow / block. The chosen segment does not light up: you are
     already on it, which is the same reason the current tab does not. */
  .tri input:not(:checked) + label:hover { background: var(--surface-2); color: var(--text); }

  label.check:hover { background: var(--surface-2); }

  .brand:hover { background: var(--surface-2); }

  .disclose > summary:hover { color: var(--accent-ink); }
  .disclose.danger > summary:hover { color: var(--danger-ink); }
  .result-plist summary:hover { color: var(--accent-ink); }

  /* A link in a notice draws its colour from the notice, so `a:hover` - one
     specificity point lighter than `.notice a` - was being dropped and the
     link was the only one on the page that did not answer. It cannot go blue
     on an amber wash, so it takes a wash of its own colour, as `code` does in
     the same box. */
  .notice a:hover { background: color-mix(in srgb, currentColor 14%, transparent); }

  /* A whole row is a big thing to leave lit after a tap. The cells carry it,
     because in a real table row they are the only boxes there are. */
  table.grid tbody tr.linked:hover > td { background: var(--surface-2); }
}

/* ---- The phone -------------------------------------------------------- */
/* One inset for the whole page below this width: 16px from the screen edge to
   a panel, and 16px again from the panel's edge to its content. Every surface
   used to arrive at its own - 22px on a section, 20px on a table, 14px on the
   activity feed - which showed up as text starting in three different places
   down one screen. */

@media (max-width: 640px) {
  .topbar { padding: 0 16px; gap: 2px; }
  .usermenu .who { display: none; }
  main { padding: 20px 16px 48px; }
  h1 { font-size: 23px; }
  .acting-bar { padding: 10px 16px; }
  .section, .card { padding: 16px; }
  .section.tight { padding: 16px; }
  .card.solo { margin: 4vh auto; padding: 22px 18px; }
  main > .disclose, .fact-panel { padding: 16px; }
  .fact { padding: 12px 16px; }
  .stat-card { padding: 14px 16px; }
  .empty { padding: 22px 16px; }
  .events { padding: 4px 16px 8px; }
  .event .when { width: auto; }
  .danger-step { padding: 16px; }
  .table-panel > table.grid > thead > tr > th:first-child,
  .table-panel > table.grid > tbody > tr > td:first-child { padding-left: 16px; }
  .table-panel > table.grid > thead > tr > th:last-child,
  .table-panel > table.grid > tbody > tr > td:last-child { padding-right: 16px; }

  /* The tab strip scrolls, and it should be obvious that it does. Running it
     out to the screen edges is what says so: a tab cut off by the edge of the
     phone reads as "there is more that way", where one cut off 16px short of
     it reads as a rendering fault. */
  .tabs {
    margin-left: -16px; margin-right: -16px;
    padding-left: 16px; padding-right: 16px;
    scroll-padding-inline: 16px;
  }

  /* A row of settings, and the end of a device or an account: what it is on
     the left and the control on the right stops working when the left half is
     three words wide. The control goes under the words instead. */
  .setting, .danger-step {
    flex-direction: column; align-items: stretch; gap: 10px;
  }
  .danger-step p { max-width: none; }
  .danger-step > form.inline { flex-wrap: wrap; }
  .setting > .tri, .tri { align-self: flex-start; }

  /* Key on one line, value under it. `flex: 0 0 190px` of key left 100px for a
     value on a 390px screen. */
  .cfgpairs > div { flex-direction: column; gap: 0; padding: 6px 0; }
  .cfgpairs dt { flex: none; }
  .cfgpairs .from { margin-left: 0; }
  .cfglayers { padding-left: 12px; }

  /* A field and the button that acts on it get a line each. Two 180px fields
     sharing a 358px panel is two fields too narrow to read what is in them. */
  .inline label, .inline label.f-short, .field-row label { flex: 1 1 100%; }
  .narrow, .field-narrow { max-width: none; }

  .steps > li { padding-left: 38px; }
  .fact-groups { gap: 14px 32px; }
}

/* ---- Tables on a phone ------------------------------------------------ */
/* A five-column table has nowhere to go on a 390px screen. `width: 100%` in a
   scrolling wrapper gave the worst of both: the table fell back to its
   min-content width, so every cell wrapped to one word a line, and the last
   columns still fell off the right-hand edge with nothing to say they were
   there - the Devices page hid the one column that says whether a device is
   online.
 *
 * So below this width a row stops being a row and becomes a block: the first
 * cell is its heading, and every other cell is its column name and its value
 * on one line. Nothing is hidden and nothing scrolls sideways. Tables opt in
 * with `.stack`, because an editor like the managed-configuration grid wants
 * different treatment, and each cell carries the column name in `data-label`
 * (the header row is gone, so it has nowhere else to come from). */

@media (max-width: 640px) {
  table.grid.stack, table.grid.stack tbody,
  table.grid.stack tr, table.grid.stack td { display: block; width: 100%; }
  table.grid.stack thead { display: none; }
  table.grid.stack tr { padding: 14px 16px; border-top: 1px solid var(--border); }
  table.grid.stack tbody tr:first-child { border-top: 0; }
  table.grid.stack td { padding: 0; border: 0; }
  /* The first cell is the row's name, so it is not labelled - it is the
     heading of the block. Every cell after it is a labelled line. */
  table.grid.stack td + td {
    display: flex; gap: 14px; justify-content: space-between; align-items: baseline;
    margin-top: 7px; text-align: right;
  }
  table.grid.stack td + td::before {
    content: attr(data-label);
    flex: none; text-align: left;
    font-size: 12px; font-weight: 650; letter-spacing: .03em;
    text-transform: uppercase; color: var(--muted);
  }
  /* A cell holding only a button - remove, revoke - has no label to print and
     wants the button, not a hairline of empty space beside one. */
  table.grid.stack td.right { justify-content: flex-end; }
  table.grid.stack td.right:empty { display: none; }
  table.grid.stack td .battery { max-width: 150px; margin-left: auto; }
  table.grid.stack td .cell-sub { text-align: right; }
  table.grid.stack td:first-child .cell-sub { text-align: left; }
  /* The panel's own inset is the row's now. */
  .table-panel > table.grid.stack > tbody > tr > td:first-child,
  .table-panel > table.grid.stack > tbody > tr > td:last-child { padding: 0; }
  .table-panel > table.grid.stack > tbody > tr:last-child > td { padding-bottom: 0; }
  /* Inside a section the section's own padding is the inset, so the row adds
     none of its own - unless the table is a panel in its own right, where the
     row's padding is the only thing between the text and the panel's border.
     Zeroing it there put "6.4 GB" hard against the edge it was drawn inside. */
  .section .table-wrap:not(.table-panel) table.grid.stack tr,
  .card .table-wrap:not(.table-panel) table.grid.stack tr {
    padding-left: 0; padding-right: 0;
  }

}

/* The row is the block once it is stacked, so the row takes the highlight.
   Painting the cells left seven grey bars with white gutters between them and
   nothing at all over the row's own padding - 67% of the row, in seven
   pieces. */
@media (max-width: 640px) and (hover: hover) {
  table.grid.stack tbody tr.linked:hover > td { background: none; }
  table.grid.stack tbody tr.linked:hover { background: var(--surface-2); }
}

/* ---- The managed configuration editor on a narrow panel --------------- */
/* Three inputs and a button in a row need about 600px between them. The
   editor does not get that from the viewport width: it sits in a section's
   body, so a 768px tablet leaves it 438px and the fixed column widths gave
   the value - the one column somebody is actually typing in - 69px of it.
   Its breakpoint is therefore the width at which the section's body stops
   being wide enough, not the width at which a phone starts. Each row becomes
   a small stack: key, type, value, then remove. */

@media (max-width: 960px) {
  table.grid.cfg-table, table.grid.cfg-table tbody,
  table.grid.cfg-table tr, table.grid.cfg-table td { display: block; width: 100%; }
  table.grid.cfg-table thead { display: none; }
  table.grid.cfg-table tr.cfg-row {
    padding: 12px 0; border-top: 1px solid var(--border);
  }
  table.grid.cfg-table tbody tr:first-child { border-top: 0; }
  table.grid.cfg-table td { padding: 0 0 8px; border: 0; }
  table.grid.cfg-table td:last-child { padding-bottom: 0; }
  table.grid.cfg-table td.right { text-align: right; }
  table.grid.cfg-table tr.cfg-empty td { padding: 8px 0; }
}

/* `display: block` on a row beats the `hidden` attribute, which is how the
   config editor hides its "nothing set" line and a suggestion already taken.
   Both stacking blocks above therefore have to put it back, each at its own
   width. */
@media (max-width: 960px) {
  table.grid.cfg-table tr[hidden], table.grid.cfg-table td[hidden] { display: none; }
}
@media (max-width: 640px) {
  table.grid.stack tr[hidden], table.grid.stack td[hidden] { display: none; }
}

/* ---- The small end of the range --------------------------------------- */

@media (max-width: 400px) {
  main { padding: 18px 12px 44px; }
  .topbar { padding: 0 12px; }
  .section, .card, .section.tight, .empty,
  main > .disclose, .fact-panel, .danger-step { padding: 14px; }
  .fact, .stat-card { padding: 12px 14px; }
  .events { padding: 4px 14px 8px; }
  .table-panel > table.grid > thead > tr > th:first-child,
  .table-panel > table.grid > tbody > tr > td:first-child { padding-left: 14px; }
  .table-panel > table.grid > thead > tr > th:last-child,
  .table-panel > table.grid > tbody > tr > td:last-child { padding-right: 14px; }
  table.grid.stack tr { padding: 13px 14px; }
  .tabs { margin-left: -12px; margin-right: -12px; padding-left: 12px; padding-right: 12px; }
  h1 { font-size: 21px; }
  .card.solo { padding: 20px 16px; }
  .steps > li { padding-left: 34px; }
}

/* ---- Touch ------------------------------------------------------------ */
/* Nothing here is about width: a 27px-high button is a 27px-high button on a
   1024px tablet too. Only the pointer decides. */

@media (pointer: coarse) {
  .btn.small { min-height: 34px; padding: 8px 12px; }
  /* The whole label is the target, and a one-line label is 20px of it. The
     horizontal padding and its matching negative margin come from the base
     rule and are kept, or the label would shift 8px on a touch screen. */
  label.check { padding: 7px 8px; margin: 4px -8px; }
  .tabs a { padding: 13px 14px; }
  .disclose > summary, .result-plist summary { padding: 6px 0; }
  .usermenu-panel a { padding: 11px 10px; }
  ul.plain li { padding: 9px 0; }
  .tri label { padding: 9px 12px; }
}
