/* Plain and legible. No framework: the container has no network at runtime, and
   a CDN link is one more thing that can fail in a clinic on hotel wifi. */

:root {
  color-scheme: light dark;
  /* A neutral ramp rather than three greys. The old set had one border
     weight doing every job -- separating a row, outlining a card, and drawing
     an input -- so everything carried the same visual weight and nothing sat
     in front of anything else. */
  --bg: #f4f6f8;
  --surface: #ffffff;
  --surface-sunk: #eef1f5;
  --border: #e4e8ee;
  --border-strong: #cbd3dd;
  --text: #10151c;
  --muted: #5b6675;
  --accent: #2f6b8f;
  --accent-soft: #e8f0f6;
  --accent-text: #ffffff;
  --danger: #8f2f2f;

  /* The role-preview bar, and the only loud surface in the platform. Amber
     rather than red: previewing is a deliberate state, not an error, but it
     has to be impossible to stop noticing. */
  --warn-surface: #7a5510;
  --warn-text: #fff3dc;
  --warn-border: #96690f;

  /* Elevation, so a card, the masthead and a menu are not all one plane. */
  --lift-1: 0 1px 2px rgb(16 21 28 / 0.05), 0 1px 3px rgb(16 21 28 / 0.06);
  --lift-2: 0 1px 3px rgb(16 21 28 / 0.06), 0 4px 12px rgb(16 21 28 / 0.07);
  --radius: 6px;

  /* The masthead's height, declared rather than measured, because a sticky
     table header has to come to rest exactly below it. Stated here and applied
     to the masthead as a min-height, so the two cannot drift apart -- the
     variable is the source of truth for both. */
  --masthead-height: 3.7rem;

  /* Chart wedges. Ordered so that neighbours in the sequence are far apart in
     hue: a breakdown is sorted largest first, so wedges 1 and 2 sit next to
     each other on the circle and must not be two blues. Nine of them because
     payer mix is currently nine. */
  --chart-1: #2f6b8f;
  --chart-2: #b4693a;
  --chart-3: #4a8a5c;
  --chart-4: #8a5ca0;
  --chart-5: #b8973f;
  --chart-6: #3f7f8f;
  --chart-7: #a34f5e;
  --chart-8: #6b7f3f;
  --chart-9: #7a6a8f;
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Lifted off pure black and given a step between planes: a dark interface
       reads as cheap mainly when every surface is the same value. */
    --bg: #14171c;
    --surface: #1c2027;
    --surface-sunk: #23282f;
    --border: #2c323b;
    --border-strong: #3d454f;
    --text: #e7eaef;
    --muted: #98a3b1;
    --accent: #5599bf;
    --accent-soft: #1e2c37;
    --accent-text: #0f151a;
    --danger: #d98b8b;

    /* Already dark ground, so this one lifts rather than deepens -- the light
       value would sit almost level with the page and stop reading as a bar. */
    --warn-surface: #4a3410;
    --warn-text: #ffe8bd;
    --warn-border: #6b4c17;

    --lift-1: 0 1px 2px rgb(0 0 0 / 0.3), 0 1px 3px rgb(0 0 0 / 0.24);
    --lift-2: 0 2px 6px rgb(0 0 0 / 0.35), 0 8px 24px rgb(0 0 0 / 0.3);

    /* Lifted and desaturated: the light palette on a dark surface reads muddy,
       and a wedge has no text on it to rescue it. */
    --chart-1: #6aa9cc;
    --chart-2: #d99a6e;
    --chart-3: #7fc194;
    --chart-4: #b795c9;
    --chart-5: #d9c078;
    --chart-6: #74b3c1;
    --chart-7: #d1929c;
    --chart-8: #a9bd77;
    --chart-9: #ab9dc4;
  }
}

* {
  box-sizing: border-box;
}

/* Checkboxes and radios in the product's colour rather than the browser's.
   One line, and this application is mostly checkboxes: roles, attributes,
   sites, and every compliance form. */
:root {
  accent-color: var(--accent);
}

/* The keyboard ring, stated once. Browsers draw something by default and it is
   different in each of them, sits tight against the control, and disappears
   entirely on anything with a background. :focus-visible rather than :focus so
   a mouse click does not leave a ring behind it. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

::selection {
  background: color-mix(in srgb, var(--accent) 30%, transparent);
}

/* Everything that moves, moves because it was asked to. Somebody who has
   turned animation off in their operating system has usually done it for a
   reason, and none of the motion here carries meaning. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

a {
  color: var(--accent);
}

/* --- application chrome ------------------------------------------------- */

.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  min-height: var(--masthead-height);
  padding: 0.75rem 1.25rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--lift-1);

  /* Stays put while the page scrolls, so the way home is always one click
     away. The census and the sign-in list run to hundreds of rows, and the
     logo was the thing that scrolled off first.

     It needs its own background -- which it already had -- or rows show
     through it, and a stacking context above the tables it passes over. */
  position: sticky;
  top: 0;
  z-index: 10;
}

.masthead .wordmark {
  font-weight: 600;
  letter-spacing: -0.01em;
}

.masthead .wordmark a {
  color: inherit;
  text-decoration: none;
}

.masthead .site {
  color: var(--muted);
  font-weight: 400;
}

.whoami {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--muted);
  font-size: 0.9rem;
}

/* Off-screen until it takes focus, then pinned where the eye already is. */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 0.6rem 1rem;
  background: var(--accent);
  color: var(--accent-text);
  border-radius: 0 0 var(--radius) 0;
  text-decoration: none;
}

.skip:focus {
  left: 0;
}

/* The masthead is three things: who the customer is, what day it is, and who
   is signed in. The date sits between them and takes the slack, which is what
   stops the bar reading as two items marooned at opposite ends of a wide
   screen. */
.nav-toggle {
  display: grid;
  place-items: center;
  flex: none;
  width: 1.9rem;
  height: 1.9rem;
  padding: 0;
  border-radius: var(--radius);
  color: var(--muted);
  text-decoration: none;
  transition: background-color 120ms ease-out, color 120ms ease-out;
}

.nav-toggle:hover {
  background: var(--surface-sunk);
  color: var(--text);
}

.masthead-date {
  margin: 0 auto 0 0;
  padding-left: 1.25rem;
  color: var(--muted);
  font-size: 0.85rem;
}

.account {
  position: relative;
}

.account summary {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0.4rem 0.25rem 0.25rem;
  border-radius: 999px;
  cursor: pointer;
  color: var(--muted);
  font-size: 0.9rem;
  list-style: none;
  transition: background-color 120ms ease-out;
}

/* Safari draws its own triangle and ignores list-style. */
.account summary::-webkit-details-marker {
  display: none;
}

.account summary:hover {
  background: var(--surface-sunk);
}

.avatar {
  display: grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  flex: none;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-text);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.account .chevron {
  transition: transform 140ms ease-out;
}

.account[open] .chevron {
  transform: rotate(180deg);
}

.account-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 0.5rem);
  min-width: 15rem;
  padding: 0.75rem 1rem 0.85rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--lift-2);
  z-index: 20;
}

.account-who {
  margin: 0 0 0.6rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--border);
  line-height: 1.35;
}

.account-who strong {
  display: block;
  color: var(--text);
}

.account-who span {
  display: block;
  color: var(--muted);
  font-size: 0.82rem;
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  /* The name goes before the date does: the avatar still identifies who is
     signed in, and the date is the thing somebody actually reads. */
  .account-name { display: none; }
}

@media (max-width: 460px) {
  .masthead-date { display: none; }
}

/* The navigation sits hard against the left edge and the content takes
   everything else. It used to be a 1100px column centred in the window, which
   is the right measure for reading prose and the wrong one for this
   application: most screens here are tables of ten or more columns, and that
   cap was the entire reason they had to wrap or scroll. Widening the window
   did nothing, which is the part that made it feel broken.

   Prose does not want a 2000px line, so the measure moved from the shell to
   the things that actually read as prose -- see `.measure` below. Tables and
   grids now get the whole window. */
.layout {
  display: grid;
  /* 200px, measured rather than guessed: the longest label is "Group schedule
     builder" at 160px plus 16px of padding, so 176 is the floor and this
     leaves a little room for a longer one. The 20px it gives back goes to the
     table beside it. */
  grid-template-columns: 200px minmax(0, 1fr);
  gap: 1.5rem;
  margin: 1.5rem 0;
  padding: 0 1.25rem 0 1rem;
}

/* Collapsed: the column goes away entirely rather than narrowing to a rail of
   icons. A rail needs an icon per module and there are none; initials or
   guessed glyphs for "Auth reviews" and "Psych tracker" would be worse than
   nothing. The toggle in the masthead is how it comes back. */
[data-nav="collapsed"] .layout {
  grid-template-columns: minmax(0, 1fr);
}

[data-nav="collapsed"] nav {
  display: none;
}

/* Stays put while the content scrolls. `align-self: start` is what stops a
   grid item stretching to the row's full height, which is what makes sticky
   look like it does nothing -- the element is already as tall as its
   container, so there is nothing for it to stick against. */
nav {
  position: sticky;
  top: calc(var(--masthead-height) + 1rem);
  align-self: start;
  /* Its own scrollbar on a short window: thirty modules is taller than a
     laptop screen, and without this the bottom of the list is unreachable
     once the page itself has stopped scrolling. */
  max-height: calc(100vh - var(--masthead-height) - 2rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Room for the scrollbar so it does not sit on top of the labels. */
  padding-right: 0.25rem;
}

@media (max-width: 720px) {
  /* Stacked above the content, where sticking it would pin a full-height list
     of modules over the page. */
  nav {
    position: static;
    max-height: none;
    overflow: visible;
  }
}

@media (max-width: 720px) {
  .layout {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Kept because two templates still ask for it, and because asking for a wide
   layout should never make a page *narrower* than the default. Every layout is
   wide now, so this says so rather than setting a cap of its own. */
.layout-wide {
  max-width: none;
}

/* A readable line length, for the things that are sentences: the paragraph
   under a heading, and a form nobody wants to track across a full-width
   screen. Applied to the element rather than the shell, so a table in the same
   page is free to use the width. */
.lede,
main > p {
  max-width: 68ch;
}

/* A section heading was a label; it is now the control that opens the section,
   so it needs to look pressable without becoming another button in a column of
   links. Same treatment as before plus a chevron and a hover. */
nav h2,
.nav-section > summary {
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  opacity: 0.75;
  margin: 1.5rem 0 0.35rem;
  padding-left: 0.6rem;
}

nav h2:first-child,
.nav-section:first-of-type > summary {
  margin-top: 0;
}

.nav-section > summary {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin-left: -0.35rem;
  padding: 0.25rem 0.4rem 0.25rem 0.25rem;
  border-radius: var(--radius);
  cursor: pointer;
  list-style: none;
  transition: color 120ms ease-out, opacity 120ms ease-out;
}

.nav-section > summary::-webkit-details-marker {
  display: none;
}

.nav-section > summary:hover {
  color: var(--text);
  opacity: 1;
}

/* Pointing right when shut, down when open -- the ordinary convention, and
   the only thing on screen saying a closed section has anything in it. */
.nav-section > summary .chevron {
  flex: none;
  transform: rotate(-90deg);
  transition: transform 140ms ease-out;
}

.nav-section[open] > summary .chevron {
  transform: rotate(0deg);
}

nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

nav li a {
  display: block;
  position: relative;
  padding: 0.4rem 0.6rem;
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--muted);
  font-size: 0.925rem;
  transition: background-color 120ms ease-out, color 120ms ease-out;
}

nav li a:hover {
  background: var(--surface);
  color: var(--text);
}

/* The current page was a solid block of accent -- the loudest thing on the
   screen, competing with the content it was pointing at. A tint plus a marker
   down its edge says the same thing at the weight a signpost deserves. */
nav li a[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

nav li a[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: 0;
  top: 20%;
  bottom: 20%;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--accent);
}

main h1 {
  font-size: 1.65rem;
  line-height: 1.2;
  letter-spacing: -0.02em;
  /* Was 0.25rem, which set the lede tight enough under it to read as a
     second line of the heading rather than as a sentence about it. */
  margin: 0 0 0.5rem;
}

.lede {
  color: var(--muted);
  margin: 0 0 1.5rem;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  /* A card lifted very slightly off the page. Kept subtle deliberately: on the
     dark palette a shadow is nearly invisible and the border does the work, so
     this must not be the thing the layout depends on. */
  box-shadow: var(--lift-1);
  padding: 1.1rem 1.35rem;
}

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 0.75rem;
  margin-bottom: 1.5rem;
}

.tile {
  display: block;
  padding: 0.9rem 1.1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--lift-1);
  text-decoration: none;
  color: var(--text);
  transition: box-shadow 140ms ease-out, border-color 140ms ease-out;
}

.tile:hover {
  border-color: var(--border-strong);
  box-shadow: var(--lift-2);
}

/* The figure in the product's colour. Four identical grey boxes is what a
   dashboard looks like before anybody has decided what matters on it. */
.tile strong {
  color: var(--accent);
}

/* The number is the point of the tile and was set at body size, so "40 on the
   active census" read as a sentence rather than as a figure. A statistic that
   is the same size as the words around it is not being presented, it is being
   mentioned. */
.tile strong {
  display: block;
  margin-bottom: 0.15rem;
  font-size: 1.75rem;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.tile span {
  color: var(--muted);
  font-size: 0.87rem;
}

.badge {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--muted);
  font-size: 0.72rem;
  vertical-align: middle;
}

.empty {
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  padding: 1.5rem;
  color: var(--muted);
  text-align: center;
}

/* --- forms and buttons --------------------------------------------------- */

button,
.button {
  font: inherit;
  padding: 0.45rem 0.9rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-text);
  cursor: pointer;
  transition: background-color 120ms ease-out, transform 60ms ease-out;
}

button:hover,
.button:hover {
  background: color-mix(in srgb, var(--accent) 85%, var(--text));
}

/* A press that shows it landed. Half the reason a form feels unresponsive is
   that nothing acknowledges the click before the page reloads. */
button:active,
.button:active {
  transform: translateY(1px);
}

button[disabled],
button[disabled]:hover {
  background: var(--border);
  color: var(--muted);
  cursor: not-allowed;
  transform: none;
}

/* Both variants below are declared after `button:hover` and tie it on
   specificity, so they win and the shared hover never reaches them. Each
   therefore states its own -- without this the sign-out control and the
   delete button are the only things on the page that do not respond to the
   pointer, which reads as them being broken. */
button.link:hover {
  background: none;
  color: var(--text);
}

button.danger:hover {
  background: color-mix(in srgb, var(--danger) 85%, var(--text));
}

button.link {
  background: none;
  border: none;
  color: var(--muted);
  padding: 0;
  text-decoration: underline;
}

label {
  display: block;
  font-weight: 500;
  margin-bottom: 0.2rem;
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"],
input[type="number"],
select,
textarea {
  font: inherit;
  width: 100%;
  padding: 0.5rem 0.65rem;
  /* The stronger border weight: an input is a thing you can act on and should
     not be drawn at the same weight as the line between two table rows. */
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  transition: border-color 120ms ease-out, box-shadow 120ms ease-out;
}

input:focus,
select:focus,
textarea:focus {
  border-color: var(--accent);
}

/* A field the pointer is over reads as reachable. */
input:hover:not(:disabled),
select:hover:not(:disabled),
textarea:hover:not(:disabled) {
  border-color: var(--muted);
}

.field {
  margin-bottom: 0.9rem;
  /* Inputs are width:100%, so without a cap a full-width layout gives a text
     box a metre wide -- unusable, and it makes a short form look like a
     mistake. A field is prose-shaped: the cap belongs here, not on the shell,
     so a table on the same page still gets the whole window.

     Not applied inside a grid-shaped form: the compliance question rows place
     their fields into named areas and set their own widths. */
  max-width: 34rem;
}

.question-row .field {
  max-width: none;
}

.errors {
  border-left: 3px solid var(--danger);
  color: var(--danger);
  padding: 0.4rem 0.75rem;
  margin-bottom: 1rem;
}

/* --- sign in ------------------------------------------------------------- */

.signin {
  max-width: 340px;
  margin: 12vh auto;
  padding: 0 1.25rem;
}

.signin h1 {
  font-size: 1.2rem;
  margin: 0 0 0.25rem;
}

.signin p.lede {
  margin-bottom: 1.25rem;
}

/* Google's button, to Google's own guidance: white ground, their mark at its
   given colours, and the wording unaltered. A recoloured mark or a reworded
   label is the version people hesitate over, which is the opposite of what a
   familiar button is for. */
.button-google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  width: 100%;
  padding: 0.6rem 1rem;
  background: #fff;
  color: #1f1f1f;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  font-size: 0.95rem;
  font-weight: 500;
  text-decoration: none;
}

.button-google:hover {
  background: #f7f8f8;
  box-shadow: var(--lift-1);
}

/* A rule with the word sitting in a gap in it. The gap is painted rather than
   cut, so the label needs the page's own background behind it. */
.signin-or {
  display: flex;
  align-items: center;
  margin: 1.1rem 0;
  color: var(--muted);
  font-size: 0.85rem;
}

.signin-or::before,
.signin-or::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

.signin-or span {
  padding: 0 0.75rem;
}

/* With Google above it, the password form is the second route rather than the
   first, and a second filled button beside a primary one reads as two equal
   choices. */
.signin button.secondary {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
}

.signin button.secondary:hover {
  background: var(--surface-sunk);
}

.signin .fineprint {
  margin-top: 1.25rem;
  color: var(--muted);
  font-size: 0.8rem;
}

footer.fineprint {
  margin: 2rem 0;
  padding: 0 1.25rem 0 1rem;
  color: var(--muted);
  font-size: 0.82rem;
}

/* Sits above the masthead and travels with the reader. Loud on purpose: this
   is a state you must not be able to forget you are in, since everything it
   does looks exactly like the platform being broken. */
.preview-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 0.6rem 1rem;
  background: var(--warn-surface);
  color: var(--warn-text);
  border-bottom: 1px solid var(--warn-border);
  font-size: 0.9rem;
}

.preview-bar p {
  margin: 0;
  max-width: none;
}

.preview-bar button {
  padding: 0.35rem 0.8rem;
  font-size: 0.85rem;
  background: transparent;
  color: inherit;
  border: 1px solid currentColor;
  white-space: nowrap;
}

.preview-bar button:hover {
  background: rgba(255, 255, 255, 0.12);
}

/* So a control can sit inline in a table cell beside ordinary links. */
form.inline {
  display: inline;
}

/* --- listings and workflow states ---------------------------------------- */

table.listing {
  width: 100%;
  /* `separate` with a zero gap, not `collapse`: a collapsed table drops the
     border-radius, which is why this used to carry `overflow: hidden` to clip
     its own corners. That clip also disabled `position: sticky` on the header
     -- an ancestor with a non-visible overflow confines it -- so the header
     scrolled away on exactly the tables long enough to need it. */
  border-collapse: separate;
  border-spacing: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* `collapse` merged adjacent borders for free; `separate` does not, so each
   cell draws only its bottom edge and the last row leaves it to the table. */
table.listing tbody tr:last-child th,
table.listing tbody tr:last-child td {
  border-bottom: none;
}

/* A breakdown row: label, proportional bar, count, share. The bar is decoration
   for the number beside it, so it carries no text of its own. */
/* Qualified with table.listing so it outweighs `table.listing th`, which is
   more specific than a bare `.breakdown th` and would otherwise win. */
table.listing.breakdown th {
  font-weight: 400;
  width: 100%;
  /* Payer names run to "Blue Cross Blue Shield of Massachusetts", which is
     wider than a third of the dashboard. Nowrap here pushed it straight out
     through the side of the card. The label is the only thing in this table
     with anything to give, so it is the only thing allowed to wrap. */
  white-space: normal;
  /* These are proper nouns -- payer names and people -- not column headings.
     table.listing uppercases its th, which turns "Aetna Better Health" into
     shouting and "Ó Fearghail" into something worse. */
  text-transform: none;
  font-size: 0.92rem;
  letter-spacing: normal;
}

/* The landing page's panels. Same shape as the chart row: a floor rather than
   an even split, so a panel with a nine-row legend and one with three figures
   are not forced to the same width. */
.panel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
  gap: 1rem;
  margin-bottom: 2rem;
  /* Each cell its own height. Stretched, a panel holding three figures grows
     to match the donut beside it and reads as a card with something missing. */
  align-items: start;
}

/* Two short panels in one cell, one under the other. */
.panel-stack {
  display: grid;
  gap: 1rem;
  align-content: start;
}

.panel-grid .card,
.panel-grid .card + .card {
  margin: 0;
}

/* A panel that wants the row to itself -- the clinical summary, once there is
   one. */
.panel-full {
  grid-column: 1 / -1;
}

/* Two or three figures side by side: admissions against discharges, caseload
   against still-to-book. */
.movement {
  display: flex;
  gap: 2rem;
  margin-bottom: 0.75rem;
}

.movement-figure strong {
  display: block;
  font-size: 1.75rem;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--accent);
}

.movement-figure span {
  font-size: 0.85rem;
  color: var(--muted);
}

/* The net is a consequence of the two beside it, not a third measurement. */
.movement-net strong {
  color: var(--muted);
}

ul.plain {
  list-style: none;
  margin: 0 0 0.75rem;
  padding: 0;
}

ul.plain li {
  padding: 0.15rem 0;
}

/* Three charts across the dashboard, wrapping to two and then one. `1fr` would
   divide the row evenly and give the payer mix -- nine legend rows -- the same
   width as level of care, which has three. auto-fit with a floor lets each card
   take what it needs and the row rewrap rather than squeezing. */
.chart-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
  gap: 1rem;
  margin-bottom: 1rem;
}

/* The stacked-card spacing does not apply inside a row: `.card + .card` gives
   every card after the first a top margin, which pushed the second and third
   12px lower than the first and read as a wobble rather than a grid.

   Both selectors are needed. `.chart-row .card` alone ties with `.card + .card`
   on specificity and loses on source order, which is the same trap as
   `table.listing th` against `.breakdown th` further up. */
.chart-row .card,
.chart-row .card + .card {
  margin: 0;
}

.chart-card h2 a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dashed var(--border);
}

.chart-card h2 a:hover {
  border-bottom-color: var(--accent);
}

/* A donut and the legend that carries its numbers. Side by side where there is
   room, stacked where there is not: below about 30rem the chart and a nine-row
   legend fight for the same width and both lose. */
/* Donut above, legend under it at the full width of the card. Side by side
   was the first arrangement and it cost twice over: the chart could only be as
   big as half a narrow card, and the legend had so little width that a payer
   name had nowhere to wrap to. Stacked, both problems are the same fix. */
.breakdown-chart {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  /* Capped and centred, so the same block works in a third of the dashboard
     and on a page of its own. Without it the standalone page stretched the
     legend to seventeen hundred pixels and left the count and the share a
     hand's width from the name they belong to. */
  max-width: 36rem;
  margin: 0 auto;
}

/* On its own page there is room, and the chart is the reason to be there.

   Qualified all the way down because `.breakdown-chart .donut` is declared
   further along the file and ties this on specificity -- source order would
   otherwise decide it, and did. Third time in this stylesheet; the others are
   `table.listing th` and `.card + .card`. */
.breakdown-solo .breakdown-chart {
  max-width: 42rem;
}

.breakdown-solo .breakdown-chart .donut {
  width: min(18rem, 70%);
}

/* The detail sits in the hole in the middle, which is what the hole is for. */
.donut-wrap {
  position: relative;
  flex: none;
  width: 100%;
  display: flex;
  justify-content: center;
}

/* The whole, in the hole. Static -- it is the denominator every wedge is a
   part of, and a number that moves is no use as one. */
.donut-total {
  position: absolute;
  /* Inset, so a long figure wraps inside the hole rather than over the ring. */
  inset: 22%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  pointer-events: none;
  line-height: 1.2;
}

.donut-total strong {
  font-size: 1.75rem;
  transition: font-size 120ms ease-out;
}

/* A currency figure is wider than a count. "$2,487.50" at the resting size
   runs out of hole, so a long one is set smaller rather than picking a size
   that suits neither. */
.donut-total[data-long] strong {
  font-size: 1.15rem;
}

.donut-total span {
  font-size: 0.72rem;
  color: var(--muted);
}

.breakdown-side {
  width: 100%;
  min-width: 0;
}

/* The hovered segment. Its height is reserved rather than collapsing, so the
   legend under it does not jump every time the pointer crosses a wedge. */
.donut-detail {
  margin: 0 0 0.75rem;
  min-height: 2.6rem;
  line-height: 1.3;
  text-align: center;
}

/* The figure moved into the donut, so this panel is the label's. Kept in the
   markup because the chart may be absent -- an empty breakdown draws no donut
   and there is then nowhere else for the numbers to go. */
.breakdown-chart:has(.donut) .donut-detail .detail-figure {
  display: none;
}

.donut-detail .detail-figure strong {
  font-size: 1.1rem;
}

.breakdown-chart:has(.donut) .donut-detail[data-showing] .detail-label {
  color: var(--text);
  font-size: 0.95rem;
}

.donut-detail .detail-figure span::before {
  content: " \00b7 ";
  color: var(--muted);
}

.donut-detail .detail-label {
  display: block;
  color: var(--muted);
  font-size: 0.85rem;
  overflow-wrap: anywhere;
}

/* At rest there is no figure, only the invitation, and it should not shout. */
.donut-detail:not([data-showing]) .detail-figure {
  display: none;
}

.donut-detail:not([data-showing]) .detail-label {
  font-size: 0.8rem;
}

/* Hovering one wedge fades the others rather than highlighting the one, which
   would need a colour that is not already in the palette. */
.breakdown-chart[data-hovering] .wedge {
  opacity: 0.28;
}

/* Two selectors because a wedge that links through is wrapped in an <a>, and
   the marker goes on whichever element carries data-wedge. Matching only the
   circle silently did nothing on exactly the charts that are clickable. */
.breakdown-chart[data-hovering] .wedge[data-active],
.breakdown-chart[data-hovering] [data-active] .wedge {
  opacity: 1;
}

.breakdown-chart .legend tr[data-active] th {
  font-weight: 600;
}

.wedge,
.legend tr {
  transition: opacity 120ms ease-out;
}

.donut a {
  cursor: pointer;
}

.donut a:focus-visible .wedge {
  outline: 2px solid var(--accent);
}

.breakdown-chart .donut {
  /* Capped as well as sized: on a wide screen a card is roomy enough that a
     donut sized purely in relative units becomes a dinner plate. */
  width: min(13rem, 60%);
  height: auto;
  aspect-ratio: 1;
  display: block;
  /* A wedge is drawn as a stroke on a circle whose circumference is exactly
     100, so its dasharray is its percentage. The pattern starts at 3 o'clock,
     which is why every offset is measured back a quarter turn -- see
     business/charts.py. */
  transform: rotate(0deg);
}

.breakdown-chart .legend {
  width: 100%;
}

/* The count and the share sit next to the label, not at the far edge. */
.breakdown-chart .legend td {
  width: 1%;
  padding-left: 1.25rem;
}

.breakdown-chart .legend th {
  width: auto;
}

.wedge {
  fill: none;
  stroke-width: 7;
  /* Between the surface and the wedge, so neighbouring colours never touch and
     a thin wedge still reads as its own thing. */
  stroke: var(--chart-1);
}

/* The legend's colour chip. Square rather than round: at this size a circle
   next to text reads as a bullet point. */
.key {
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  margin-right: 0.5rem;
  border-radius: 2px;
  vertical-align: baseline;
  background: var(--chart-1);
}

.tone-1 { stroke: var(--chart-1); background: var(--chart-1); }
.tone-2 { stroke: var(--chart-2); background: var(--chart-2); }
.tone-3 { stroke: var(--chart-3); background: var(--chart-3); }
.tone-4 { stroke: var(--chart-4); background: var(--chart-4); }
.tone-5 { stroke: var(--chart-5); background: var(--chart-5); }
.tone-6 { stroke: var(--chart-6); background: var(--chart-6); }
.tone-7 { stroke: var(--chart-7); background: var(--chart-7); }
.tone-8 { stroke: var(--chart-8); background: var(--chart-8); }
.tone-9 { stroke: var(--chart-9); background: var(--chart-9); }

/* A `.key` is a span with no text, so it needs its background stated after the
   .tone rules set it -- and the .tone rules set both stroke and background so
   one class can colour a wedge and a chip alike. */

/* --- The patient-facing schedule form ------------------------------------
   One column, larger touch targets, no navigation. Almost everyone reaching it
   is on a phone, having just scanned a code on the wall. */

.public {
  max-width: 34rem;
  margin: 0 auto;
  padding: 1.5rem 1rem 3rem;
}

.public-mark {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}

.public-mark strong { font-size: 1rem; }
.public-mark span { color: var(--muted); font-size: 0.87rem; }

.public .lede { font-size: 1.15rem; color: var(--text); margin-bottom: 0.35rem; }

/* Thumb-sized rather than pointer-sized. */
.public input[type="text"],
.public input[type="date"],
.public textarea,
.public select,
.public button {
  font-size: 1rem;
  padding: 0.7rem 0.75rem;
}

.public input[type="radio"] {
  width: 1.15rem;
  height: 1.15rem;
}

.weekline {
  background: var(--bg);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  padding: 0.75rem 0.9rem;
  margin-bottom: 1rem;
}

.weekline strong { display: block; }
.weekline span { color: var(--muted); font-size: 0.85rem; }

.day-block {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.85rem 1rem;
  margin-bottom: 0.75rem;
  /* A fieldset defaults to min-width: min-content, which lets a textarea inside
     push it wider than the phone it is being filled in on. */
  min-width: 0;
}

/* Widgets carry a cols or size attribute; on a 375px screen that is wider than
   the card holding them. */
.public input,
.public textarea,
.public select {
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

.public ul { list-style: none; }

.public label {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.3rem 0;
}

.public input[type="radio"] { width: auto; flex: none; }

/* Hidden only once the script has run, so a patient with JavaScript off still
   sees the box and can still explain an absence. */
.reason-hidden { display: none; }

.day-block legend {
  font-weight: 600;
  padding: 0 0.35rem;
}

/* The sign-in confirmation is the whole interface, read by somebody already
   turning away from the screen, so the name and the time carry it. */
.signed-in-name {
  font-size: clamp(1.6rem, 7vw, 2.4rem);
  font-weight: 600;
  line-height: 1.1;
}

.signed-in-time {
  font-size: clamp(2.2rem, 11vw, 3.4rem);
  font-weight: 600;
  color: var(--accent);
  line-height: 1.1;
  margin: 0.5rem 0 0.25rem;
}

/* A tablet on the wall, read from across a room. Sized against the viewport so
   it fills whatever it is put on, and always on white -- a QR rendered dark on
   a dark page is not a QR, it is a picture of one. */
.display {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  padding: 2rem 1rem;
  text-align: center;
}

.display h1 { font-size: clamp(1.5rem, 4vw, 2.75rem); }

.display-qr {
  background: #fff;
  padding: clamp(0.75rem, 2vw, 1.5rem);
  border-radius: var(--radius);
  line-height: 0;
}

/* The library sizes its SVG in millimetres, which a screen renders at about
   150px however large the screen is. */
.display-qr svg {
  width: min(58vh, 78vw);
  height: auto;
}

.display-week {
  color: var(--muted);
  font-size: clamp(0.95rem, 1.8vw, 1.35rem);
}

/* --- The printable access code ------------------------------------------- */

.qr-sheet {
  text-align: center;
  padding: 1.5rem;
}

.qr-sheet svg {
  width: 100%;
  max-width: 320px;
  height: auto;
  background: #fff;
  padding: 0.75rem;
  border-radius: var(--radius);
  box-sizing: border-box;
}

.qr-sheet code {
  display: inline-block;
  margin-top: 0.75rem;
  word-break: break-all;
}

@media print {
  .masthead, nav, .filters, .fineprint, .no-print { display: none !important; }
  .qr-sheet svg { max-width: 420px; }
}

/* The timetable grid: a cell is a short stack of names to tick, so the ticks
   want to be compact and the whole week wants to be on one screen. */
.timetable-grid td { vertical-align: top; }

.timetable-grid .tick {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.12rem 0;
  font-size: 0.82rem;
  cursor: pointer;
  white-space: nowrap;
}

.timetable-grid .tick input { margin: 0; flex: none; }
.timetable-grid th a { text-decoration: none; }
.timetable-grid th .hint { margin: 0; }

/* --- The weekly calendar -------------------------------------------------
   A column per day with entries in time order, rather than a time grid. Two
   clinicians genuinely overlap, and a grid has to either lie about that or
   squeeze columns until nothing is readable. */
.week-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 0.75rem;
  align-items: start;
}

@media (max-width: 900px) {
  .week-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 560px) {
  .week-grid { grid-template-columns: minmax(0, 1fr); }
}

.day-column h2 {
  font-size: 0.9rem;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.6rem;
}

.day-column h2 span {
  color: var(--muted);
  font-weight: 400;
  font-size: 0.82rem;
}

.entry {
  border-left: 3px solid var(--border);
  padding: 0.4rem 0 0.4rem 0.6rem;
  margin-bottom: 0.5rem;
  font-size: 0.85rem;
}

.entry strong,
.entry span { display: block; }

.entry strong { font-weight: 600; }

.entry .hint { font-size: 0.78rem; margin: 0; }

/* A group is the fixed structure of the day; a one-to-one is booked around it,
   so the two want telling apart at a glance. */
.entry-group { border-left-color: var(--muted); }
.entry-session { border-left-color: var(--accent); }

/* A table too wide for its card scrolls inside it, rather than squeezing a
   column until names break mid-word or pushing the whole page sideways. For
   grids with a column per weekday, where there is no width left to give. */
.table-scroll {
  overflow-x: auto;
}

/* `anywhere` rather than `break-word`: only the former lets a long token shrink
   the column's min-content width, which is what stops one very long surname
   pushing a table wider than the card holding it. The seed data carries such a
   name precisely so this gets found. */
table.listing td:not(.nowrap) {
  overflow-wrap: anywhere;
}

/* Short values that read badly broken across lines: a level of care, a date.
   Applied per column rather than to the table, because a name or a postal
   address should still wrap.

   An email address belongs here too, though it is not short. `overflow-wrap:
   anywhere` breaks it between arbitrary letters, which leaves an identifier
   nobody can read at a glance or select cleanly -- and the address is the
   thing that column exists to show. A table that refuses to break one needs
   somewhere to put the overflow, so the listing goes inside `.table-scroll`. */
.nowrap { white-space: nowrap; }

table.listing th,
table.listing td {
  text-align: left;
  /* Was 0.5rem/0.75rem. Dense rows read as a spreadsheet export; a little
     room reads as something that was laid out. Costs about one row of the
     forty on screen. */
  padding: 0.65rem 0.85rem;
  border-bottom: 1px solid var(--border);
}

/* The column headings stay while the body scrolls under them. The census runs
   to hundreds of rows and by row eighty there is nothing on screen saying which
   column is the admission date and which is the date of birth -- both are
   dates, and guessing wrong about a patient's admission is not a small error.

   It comes to rest below the masthead, which is itself sticky; both read the
   same variable so they cannot drift apart. The background is required, not
   decoration: without it the rows show through as they pass underneath. */
table.listing thead th {
  position: sticky;
  top: var(--masthead-height);
  z-index: 1;
  /* Distinct from the rows beneath it. The header used to be the same white as
     the body, separated only by a hairline, so a table read as a list with a
     bold first row rather than as a table with a header. */
  background: var(--surface-sunk);
  border-bottom: 1px solid var(--border-strong);
}

/* Not inside a horizontal scroller. `.table-scroll` sets `overflow-x: auto`,
   which makes `overflow-y` compute to `auto` as well, and that turns it into a
   scroll container -- so a sticky header sticks relative to *it* rather than to
   the page, and `top: 59px` pushes the heading 59 pixels down over its own
   first rows. There is nothing to stick to in a box that only scrolls
   sideways, so it does not try. */
.table-scroll table.listing thead th {
  position: static;
}

/* Rounded with the table, since the header is now filled and its square
   corners would otherwise poke out past the card's radius. */
table.listing thead tr:first-child th:first-child {
  border-top-left-radius: var(--radius);
}

table.listing thead tr:first-child th:last-child {
  border-top-right-radius: var(--radius);
}

/* Lining figures of equal width, so a column of counts and dates lines up
   digit under digit instead of drifting. Costs nothing and is most of what
   separates a table that looks typeset from one that looks emitted. */
table.listing,
.tile strong,
.donut-total strong,
.donut-detail {
  font-variant-numeric: tabular-nums;
}

/* Numbers right, so the units line up under each other and a 9 next to a 11
   reads as smaller. Applied per column with a class rather than by guessing
   which cells are numeric: a member id and a phone number are digits and are
   not quantities, and right-aligning those would look like a mistake. */
table.listing th.num,
table.listing td.num {
  text-align: right;
}

/* A row under the pointer, on lists that are read by scanning across: the
   census and the sign-in sheet run to hundreds of rows and losing your line
   halfway across is the ordinary way to misread one. */
table.listing tbody tr:hover td,
table.listing tbody tr:hover th {
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}

table.listing th {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

table.listing tr:last-child td {
  border-bottom: none;
}

.state {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.8rem;
  border: 1px solid var(--border);
}

.state-pending_recommendation,
.state-pending_approval,
.state-pending {
  border-color: var(--accent);
  color: var(--accent);
}

.state-collected {
  border-color: #2f8f5b;
  color: #2f8f5b;
}

/* A refusal reads as red and a no-show does not, because in this programme a
   refused screen is clinically meaningful and an absence is an absence. */
.state-refused {
  border-color: var(--danger);
  color: var(--danger);
}

.state-not_collected,
.state-cancelled {
  color: var(--muted);
}

/* Transport queue statuses. Requested and being-arranged are both "somebody
   still has to do this", which is what the list is for. */
.state-requested,
.state-in_progress {
  border-color: var(--accent);
  color: var(--accent);
}

.state-active {
  border-color: #2f8f5b;
  color: #2f8f5b;
}

.state-ended,
.state-not_needed {
  color: var(--muted);
}

/* Patient schedule statuses. Late is amber rather than red: they are coming,
   which is a different thing from an absence. */
.state-attending {
  border-color: #2f8f5b;
  color: #2f8f5b;
}

.state-planned_late {
  border-color: #b8860b;
  color: #d9a441;
}

.state-planned_absence {
  border-color: var(--danger);
  color: var(--danger);
}

.state-not_scheduled {
  color: var(--muted);
}

.state-approved {
  border-color: #2f8f5b;
  color: #2f8f5b;
}

.state-denied {
  border-color: var(--danger);
  color: var(--danger);
}

.state-withdrawn {
  color: var(--muted);
}

.badge.warn {
  border-color: var(--danger);
  color: var(--danger);
}

.hint {
  color: var(--muted);
  font-size: 0.87rem;
  margin: 0.2rem 0 0;
}

.field-error {
  color: var(--danger);
  font-size: 0.87rem;
  margin: 0.2rem 0 0;
}

button.danger {
  background: var(--danger);
}

/* Was 0.95rem against a 15px body -- a fifth of a pixel larger than the text
   it introduced, which is not a hierarchy. Size alone would have to go a long
   way to separate them, so it takes weight and spacing instead: the eye reads
   the gap under a heading as much as the letters in it. */
.card h2 {
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 0.85rem;
}

.card + .card {
  margin-top: 0.75rem;
}

.card ul {
  margin: 0;
  padding-left: 1.1rem;
}

code.wrap {
  display: block;
  word-break: break-all;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.5rem 0.65rem;
  font-size: 0.85rem;
}

ul.checkboxselectmultiple,
.field ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.field ul li label {
  font-weight: 400;
  display: flex;
  gap: 0.4rem;
  align-items: baseline;
}

.field.grant {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 150px;
  gap: 0.25rem 1rem;
  align-items: baseline;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0;
}

.field.grant:last-child { border-bottom: none; }

.field.grant label {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85rem;
  font-weight: 400;
  margin: 0;
}

.field.grant .hint {
  grid-column: 1;
  grid-row: 2;
}

.field.grant select,
.field.grant input[type="checkbox"] {
  grid-column: 2;
  grid-row: 1 / span 2;
  justify-self: end;
}

.field.grant select {
  font: inherit;
  padding: 0.25rem 0.4rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--text);
  width: 100%;
}

.filters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.75rem;
  align-items: end;
  margin-bottom: 1rem;
}

.filters .field { margin-bottom: 0; }

/* Only the size differs. This used to restate the whole control -- border,
   background, radius -- with the older tokens, so the filter bar quietly drew
   its controls one weight lighter than every other field in the application
   and looked like a different product. Everything but the padding now comes
   from the shared rule above. */
.filters select,
.filters input[type="date"] {
  padding: 0.35rem 0.5rem;
}

.state-denied {
  border-color: var(--danger);
  color: var(--danger);
}

/* --- brand marks --------------------------------------------------------- */

.masthead .wordmark a {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  /* The name is one line or nothing. Left to wrap it stacks into three lines on
     a narrow window and shoves the sign-out control off the bar. */
  white-space: nowrap;
}

@media (max-width: 460px) {
  /* No room for both. The mark still says whose this is. */
  .masthead .wordmark span {
    display: none;
  }
}

.masthead .mark {
  height: 28px;
  width: auto;
  display: block;
}

.signin-logo {
  margin: 0 0 1.25rem;
}

.signin-logo img {
  display: block;
  width: 240px;
  max-width: 100%;
  height: auto;
}

/* A checkbox belongs beside its label, not under it. :has() rather than a
   modifier class, so _field.html stays one template for every field type --
   where it is unsupported the layout falls back to the stacked default, which
   is legible, just less tidy. */

.field:has(> input[type="checkbox"]) {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 0.55rem;
  align-items: start;
}

.field:has(> input[type="checkbox"]) > label {
  grid-column: 2;
  grid-row: 1;
  font-weight: 400;
  margin: 0;
}

.field:has(> input[type="checkbox"]) > input[type="checkbox"] {
  grid-column: 1;
  grid-row: 1;
  margin-top: 0.25rem;
}

.field:has(> input[type="checkbox"]) > .hint,
.field:has(> input[type="checkbox"]) > .field-error {
  grid-column: 2;
}

/* One question in the form editor. Nested cards need a lighter ground than the
   card they sit in, or the rows disappear into it. */

.card .card.question-row {
  background: var(--bg);
  margin-bottom: 0.75rem;

  /* A question has nine inputs and most of them are short. Stacked, eight
     questions ran to four thousand pixels; paired, they fit on a screen and a
     half. Named areas rather than source order, because the field order that
     reads well in the form class is not the one that lays out well. */
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0 1rem;
  grid-template-areas:
    "label     label     label        type"
    "help_text help_text required     allows_other"
    "choices   choices   prefill      prefill"
    "ORDER     DELETE    DELETE       DELETE";
}

.question-row > .label { grid-area: label; }
.question-row > .type { grid-area: type; }
.question-row > .required { grid-area: required; }
.question-row > .help_text { grid-area: help_text; }
.question-row > .choices { grid-area: choices; }
.question-row > .allows_other { grid-area: allows_other; }
/* The area is `prefill`, not `default`: CSS reserves `default` as an ident, so
   `grid-area: default` is dropped as invalid and the cell auto-places instead
   -- silently, and only visible as a textarea half the width it should be. */
.question-row > .default { grid-area: prefill; }
.question-row > .ORDER { grid-area: ORDER; }
.question-row > .DELETE { grid-area: DELETE; }

/* Inputs carry a size or cols attribute from the widget, which in a grid cell
   leaves them stopping short of the column they were placed in. */
.question-row input[type="text"],
.question-row select,
.question-row textarea {
  width: 100%;
  box-sizing: border-box;
}

/* The two checkboxes sit beside text inputs, so they need the label's height
   above them or they float against the top of their cell. */
.question-row > .required,
.question-row > .allows_other,
.question-row > .DELETE {
  align-self: end;
}

@media (max-width: 800px) {
  .card .card.question-row {
    display: block;
  }
}

/* The notification exactly as the biller sent it, on a review's own page.
   Monospaced and preserved: the whole reason it is kept is so a person can
   compare what the parser made against what actually arrived, and reflowing
   it would defeat that. It wraps rather than scrolling -- a notification is
   three short lines, and a horizontal scrollbar on three short lines reads as
   though something is hidden. */
pre.source {
  margin: 0;
  padding: 0.75rem 1rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85rem;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Columns whose content is a short fixed vocabulary: a status pill, a couple of
   attribute badges, a single "Open" link. `width: 1%` is the shrink-to-fit
   trick -- a percentage below the column's minimum content width makes the
   browser give it exactly that minimum and hand every remaining pixel to the
   auto-width columns. Without it a table divides its width roughly evenly, so
   a Status column sits half empty while the email address beside it wraps onto
   a second line and doubles the height of every row. */
/* A listing where every column is a short identifier -- a name, an address, a
   role, a status -- and none of them reads well broken across two lines. Rather
   than deciding column by column which one may wrap, nothing wraps and the
   table scrolls inside its card when the window is too narrow.

   Chosen after doing it the other way. Making one column no-wrap hands its
   full width demand to the others, so the wrap moves rather than going away:
   fixing the email address pushed the name and the role onto two lines each.
   The width has to come from somewhere, and a scrollbar is the only place that
   is not another column. Use it only where every column is genuinely short --
   a free-text note or a postal address still belongs in a wrapping cell. */
table.listing.no-wrap th,
table.listing.no-wrap td {
  white-space: nowrap;
  overflow-wrap: normal;
}

table.listing th.shrink,
table.listing td.shrink {
  width: 1%;
  /* `overflow-wrap: anywhere` is set on every ordinary cell so one long surname
     cannot widen the table. Here it is actively harmful: it lets a word break
     between any two letters, which makes the column's minimum content width a
     single character, and `width: 1%` then collapses the column to it. "Open"
     came out as "Op / en" in a 36px column. */
  overflow-wrap: normal;
  /* Two pills in one cell ("Active" and "vendor") stay side by side. Letting
     them stack saves eight pixels of column and costs a whole extra line on
     that row, which is the trade this class exists to avoid. */
  white-space: nowrap;
}

/* A pill is a label, not a paragraph. Wrapping one puts the words in the middle
   of a tall oval with blank space above and below them, which reads as a
   rendering fault rather than a status. They are all one or two short words, so
   there is nothing to lose by refusing. */
.badge,
.state {
  white-space: nowrap;
}
