/*
 * Admin application styling.
 *
 * Plain CSS against the tokens, no framework and no build step. The admin surface is small -
 * settings, two lists, metrics, billing - and a component framework would cost more in tooling
 * than it saves in markup.
 */

*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--page);
  color: var(--ink-body);
  font-family: var(--font-ui);
  font-size: var(--text-base);
  line-height: 1.5;
}

/* ---------------------------------------------------------------- masthead */

.masthead {
  border-bottom: 2px solid var(--rule-strong);
  background: var(--page);
  padding: var(--space-5) var(--space-4) var(--space-4);
  text-align: center;
}

.masthead__eyebrow {
  font-family: var(--font-editorial);
  font-size: var(--text-xs);
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 var(--space-1);
}

.masthead__title {
  font-family: var(--font-editorial);
  font-size: var(--text-masthead);
  font-weight: normal;
  color: var(--ink);
  margin: 0;
}

/* ---------------------------------------------------------------- layout */

.shell {
  max-width: var(--measure);
  margin: 0 auto;
  padding: var(--space-5) var(--space-4) var(--space-7);
}

.nav {
  position: relative;
  display: flex;
  align-items: center;
  border-bottom: var(--border);
  padding: var(--space-2) var(--space-4);
  background: var(--page);
}

.nav__links {
  display: flex;
  flex: 1;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* Every place in a bar - here and on the public site - looks like a link the moment a pointer
   reaches it. Hovering used to move one grey to a slightly darker grey, which nobody noticed;
   now the link fills with the accent colour, which nobody can miss. */
.nav__links a,
.nav__signout,
.site-nav__links a {
  display: inline-block;
  padding: var(--space-1) var(--space-2);
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--ink-body);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  line-height: 1.5;
  letter-spacing: 1px;
  text-transform: uppercase;
  text-decoration: none;
}

.nav__links a:hover,
.nav__links a:focus-visible,
.nav__signout:hover,
.nav__signout:focus-visible,
.site-nav__links a:hover,
.site-nav__links a:focus-visible {
  background: var(--accent);
  color: var(--accent-text);
}

.nav__links a[aria-current="page"],
.site-nav__links a[aria-current="page"] {
  color: var(--ink);
  box-shadow: inset 0 -2px 0 var(--ink);
}

.nav__links a[aria-current="page"]:hover,
.site-nav__links a[aria-current="page"]:hover {
  color: var(--accent-text);
}

/* Signing out is the only thing in the navigation that is not a place, so it sits apart from
   the ones that are. Reads as part of the navigation rather than as a form control, but it is a
   real button, because it does something rather than going somewhere. */
.nav__signout {
  margin-left: auto;
}

/* The page you are on, named in the bar when the links fold away on a phone. */
.nav__current {
  display: none;
  color: var(--ink);
  font-size: var(--text-sm);
  font-weight: bold;
  letter-spacing: 1px;
  text-transform: uppercase;
}

/* The Menu button. Only on a phone, and only once the script that works it has run: without it
   the links stay in the page, wrapped, as they always were. */
.nav-toggle {
  display: none;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  margin-left: auto;
  padding: 0 var(--space-3);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--surface-raised);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  letter-spacing: 1px;
  text-transform: uppercase;
}

.nav-toggle:hover {
  border-color: var(--ink);
}

.nav-toggle__icon,
.nav-toggle__icon::before,
.nav-toggle__icon::after {
  display: block;
  width: 18px;
  height: 2px;
  background: currentColor;
}

.nav-toggle__icon {
  position: relative;
}

.nav-toggle__icon::before,
.nav-toggle__icon::after {
  content: "";
  position: absolute;
  left: 0;
}

.nav-toggle__icon::before {
  top: -6px;
}

.nav-toggle__icon::after {
  top: 6px;
}

/* Open, the three bars turn into a cross: the same button closes it. */
.nav-toggle[aria-expanded="true"] .nav-toggle__icon {
  background: transparent;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__icon::before {
  top: 0;
  transform: rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__icon::after {
  top: 0;
  transform: rotate(-45deg);
}

@media (max-width: 40rem) {
  [data-nav-menu] .nav-toggle {
    display: inline-flex;
  }

  [data-nav-menu] .nav__current {
    display: block;
  }

  /* The dropdown: under the bar, over the page, one link to a row, each as tall as a fingertip. */
  [data-nav-menu] .nav__links,
  [data-nav-menu] .site-nav__links {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 20;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--space-2) var(--space-4) var(--space-3);
    border-bottom: var(--border);
    background: var(--page);
    box-shadow: 0 10px 18px rgba(26, 26, 26, 0.12);
  }

  [data-nav-menu="closed"] .nav__links,
  [data-nav-menu="closed"] .site-nav__links {
    display: none;
  }

  [data-nav-menu] .nav__links > *,
  [data-nav-menu] .site-nav__links > * {
    display: flex;
    align-items: center;
    width: 100%;
    min-height: 48px;
    margin: 0;
    padding: 0 var(--space-3);
    font-size: var(--text-base);
    text-align: left;
  }

  [data-nav-menu] .nav__links > * + *,
  [data-nav-menu] .site-nav__links > * + * {
    border-top: var(--border);
  }

  /* A bar down the side rather than underneath, which in a list reads as "you are here". */
  [data-nav-menu] .nav__links a[aria-current="page"],
  [data-nav-menu] .site-nav__links a[aria-current="page"] {
    box-shadow: inset 3px 0 0 var(--ink);
  }
}

/* Present for a screen reader, absent for everybody else. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.card {
  background: var(--surface);
  border: var(--border);
  border-radius: var(--radius);
  padding: var(--space-5);
  margin-bottom: var(--space-5);
  box-shadow: var(--shadow-soft);
}

.card__title {
  font-family: var(--font-editorial);
  font-size: var(--text-xl);
  font-weight: normal;
  color: var(--ink);
  margin: 0 0 var(--space-2);
}

.card__hint {
  color: var(--ink-muted);
  font-size: var(--text-sm);
  margin: 0 0 var(--space-4);
}

/* ---------------------------------------------------------------- forms */

.field {
  margin-bottom: var(--space-4);
}

.field label {
  display: block;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: var(--space-1);
}

.field__hint {
  display: block;
  font-size: var(--text-xs);
  color: var(--ink-muted);
  margin-top: var(--space-1);
  font-weight: normal;
}

.field__hint a {
  color: var(--ink-body);
}

.field__hint a:hover {
  color: var(--ink);
}

input[type="text"],
input[type="email"],
input[type="number"],
select {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--surface-raised);
  color: var(--ink-body);
  font-family: var(--font-ui);
  font-size: var(--text-field);
}

input:focus,
select:focus,
button:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* The address of the person being renamed. It has to look unavailable, or an admin tries to
   type in it and nothing happens; and it has to stay fixed, because editing it would quietly
   rename somebody else instead. */
.field input[readonly] {
  background: var(--page);
  color: var(--ink-muted);
  cursor: not-allowed;
}

.field--invalid input,
.field--invalid select {
  border-color: var(--danger);
}

.field__error {
  display: block;
  color: var(--danger);
  font-size: var(--text-xs);
  margin-top: var(--space-1);
}

.row {
  display: flex;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.row > * {
  /* 150px so cadence, day and hour fit on one line at the content width; they wrap to full
     width below 520px rather than squeezing into unreadable columns. */
  flex: 1 1 150px;
}

/* ---------------------------------------------------------------- buttons */

button {
  font-family: var(--font-ui);
  font-size: var(--text-base);
  padding: var(--space-2) var(--space-5);
  border-radius: var(--radius);
  border: 1px solid transparent;
  cursor: pointer;
}

.button--primary {
  background: var(--accent);
  color: var(--accent-text);
}

/* Quieter than primary, but plainly a button and plainly the accent's: a plain outline in the
   rule colour sat back as far as a disabled control. */
.button--secondary {
  background: var(--secondary);
  border-color: var(--secondary-border);
  color: var(--accent);
}

.button--secondary:hover:not([disabled]) {
  background: var(--secondary-hover);
  border-color: var(--accent);
}

/* The button classes work on a link too, for something that goes somewhere but should look like
   an action. A link has none of a button's box, so it is given one here; without it the class
   only changed the colour of some underlined text. */
a.button--primary,
a.button--secondary {
  display: inline-block;
  padding: var(--space-2) var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-family: var(--font-ui);
  font-size: var(--text-base);
  line-height: normal;
  text-align: center;
  text-decoration: none;
}

a.button--secondary {
  border-color: var(--secondary-border);
}

button[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
}

/* An anchor that should read as an action. Browser-default link blue belongs to no part of
   this design, and a real <button> would be wrong for something that navigates. */
.link-button {
  display: inline-block;
  font-family: var(--font-ui);
  font-size: var(--text-base);
  padding: var(--space-2) var(--space-5);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  color: var(--ink-body);
  text-decoration: none;
}

.link-button:hover {
  border-color: var(--ink);
}

/* ---------------------------------------------------------------- people lists */

.people {
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
  border-top: var(--border);
}

/* Past ten people the list scrolls in its own box (lists.js sets the height from the rows).

   The scrollbar is styled on purpose, not hidden: a styled scrollbar is drawn permanently where
   an unstyled one would fade out until touched. Phones fade theirs regardless, so the shadow at
   the bottom edge - which scrolls away once the end is reached - and the hint line below say
   there is more. */
.people--scrolls {
  overflow-y: auto;
  border-bottom: var(--border);
  background:
    linear-gradient(transparent, var(--surface) 70%) bottom / 100% 32px no-repeat local,
    radial-gradient(farthest-side at 50% 100%, rgba(26, 26, 26, 0.18), transparent) bottom /
      100% 12px no-repeat scroll;
}

.people--scrolls::-webkit-scrollbar {
  width: 10px;
}

.people--scrolls::-webkit-scrollbar-track {
  background: var(--surface);
}

.people--scrolls::-webkit-scrollbar-thumb {
  background: var(--rule-strong);
  border-radius: 5px;
  border: 2px solid var(--surface);
}

/* Firefox only. Chrome ignores the ::-webkit-scrollbar rules above once these are set, and
   those rules are what keep its scrollbar on screen. */
@supports not selector(::-webkit-scrollbar) {
  .people--scrolls {
    scrollbar-width: thin;
    scrollbar-color: var(--rule-strong) var(--surface);
  }
}

.people--scrolls .people__row {
  padding-right: var(--space-3);
}

.people__hint {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
}

.people__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-bottom: var(--border);
}

.people__who {
  font-size: var(--text-sm);
  color: var(--ink-body);
  overflow-wrap: anywhere;
}

.people__note {
  flex: 0 0 auto;
  font-size: var(--text-xs);
  font-style: italic;
}

.people__action {
  flex: 0 0 auto;
  font-size: var(--text-xs);
  padding: var(--space-1) var(--space-3);
}

/* Wraps rather than squeezing: two buttons and a long address do not fit a phone on one line,
   and a shrunken Remove is a Remove that gets mis-hit. */
.people__actions {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

/* ---------------------------------------------------------------- unsubscribe */

.choices {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  margin: var(--space-5) 0 0;
}

/* The two options are separated so the destructive one is never pressed by momentum. */
.choices button + p {
  margin: 0 0 var(--space-4);
}

.choices__keep {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: var(--border);
}

/* ---------------------------------------------------------------- figures */

.figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-5);
  margin: 0;
}

.figure dt {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  letter-spacing: 1px;
  text-transform: uppercase;
}

.figure dd {
  margin: var(--space-1) 0 0;
  font-family: var(--font-editorial);
  font-size: 42px;
  line-height: 1.1;
  color: var(--ink);
}

.figure__note {
  margin: var(--space-2) 0 0;
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

/* On the overview the figures sit under the newsletter rather than being the page, so they are
   sized to be read rather than announced. Four fit on one row at the smaller measure. */
.figures--compact {
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--space-4);
}

.figures--compact .figure dd {
  font-size: 26px;
}

/* Who sent the waiting articles, behind a button. A stacked list rather than a table: three
   columns of address, date and title do not fit a phone. */
.waiting {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: var(--border);
}

.waiting__list {
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
  border-top: var(--border);
}

.waiting__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-bottom: var(--border);
}

.waiting__words {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.waiting__title {
  font-family: var(--font-editorial);
  font-size: var(--text-lg);
  color: var(--ink);
  overflow-wrap: anywhere;
}

.waiting__detail {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------- feedback */

.notice {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius);
  border: var(--border);
  margin-bottom: var(--space-4);
  font-size: var(--text-sm);
  scroll-margin-top: var(--space-5);
}

/* A ground of their own colour as well as the text and border. Dark green text on the page's
   own background read as nearly black, and a saved form looked the same as an unsaved one. */
.notice--success {
  border-color: var(--success);
  background: var(--success-wash);
  color: var(--success);
}

.notice--error {
  border-color: var(--danger);
  background: var(--danger-wash);
  color: var(--danger);
}

.notice--arrived {
  animation: notice-arrive 300ms ease-out;
}

@keyframes notice-arrive {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
}

/* ---------------------------------------------------------------- action status

   Beside a button: a spinner while it works, then a green tick (shared-ui.js actionStatus). */
.action-status {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  margin-left: var(--space-3);
  vertical-align: middle;
}

.form-actions .action-status {
  margin-left: 0;
}

.action-status[data-status="working"]::before {
  content: "";
  width: 18px;
  height: 18px;
  border: 3px solid var(--secondary);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: action-spin 0.8s linear infinite;
}

.action-status[data-status="done"]::before,
.action-status[data-status="fading"]::before {
  content: "";
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--success);
}

/* The tick: two sides of a box, turned. */
.action-status[data-status="done"]::after,
.action-status[data-status="fading"]::after {
  content: "";
  position: absolute;
  top: 5px;
  left: 9px;
  width: 7px;
  height: 12px;
  border: solid var(--accent-text);
  border-width: 0 3px 3px 0;
  transform: rotate(45deg);
}

.action-status[data-status="done"] {
  animation: action-pop 200ms ease-out;
}

.action-status[data-status="fading"] {
  opacity: 0;
  transition: opacity 600ms ease;
}

@keyframes action-spin {
  to {
    transform: rotate(360deg);
  }
}

@keyframes action-pop {
  from {
    transform: scale(0.6);
  }
}

/* ---------------------------------------------------------------- a row that was removed

   Red for two seconds, saying so, then it fades and folds away (shared-ui.js removeRow). */
.row--removed {
  background: var(--danger-wash);
  box-shadow: inset 3px 0 0 var(--danger);
  padding-left: var(--space-3);
  padding-right: var(--space-3);
  overflow: hidden;
}

.row--removed > :not(.row__removed-note) {
  color: var(--danger);
}

.row__removed-note {
  flex: 0 0 auto;
  color: var(--danger);
  font-size: var(--text-sm);
  font-weight: bold;
}

.row--leaving {
  opacity: 0;
  padding-top: 0;
  padding-bottom: 0;
  border-bottom-width: 0;
  transition:
    opacity 400ms ease,
    max-height 400ms ease,
    padding 400ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .notice--arrived,
  .action-status[data-status="done"] {
    animation: none;
  }

  .row--leaving,
  .action-status[data-status="fading"] {
    transition: none;
  }
}

/* The `hidden` attribute is only honoured by a rule in the browser's own stylesheet, and every
   author rule beats that one whatever its specificity. So any class here that sets `display`
   silently un-hides an element that JavaScript has marked hidden - which is how the note about
   days after the 28th appeared on a weekly newsletter, where there are no dates to restrict.
   Stated once, for every class, rather than patched per class as it is noticed. */
[hidden] {
  display: none !important;
}

.next-send {
  font-family: var(--font-editorial);
  font-size: var(--text-lg);
  color: var(--ink);
}

.muted {
  color: var(--ink-muted);
  font-size: var(--text-sm);
}

@media (max-width: 520px) {
  .row > * {
    flex-basis: 100%;
  }
}

/* ---------------------------------------------------------------- ending */

/* Used only for the two irreversible actions. Muted rather than alarming: this is a family
   newspaper, and a shouting red button would be out of key with everything around it. */
/* Turning somebody away - quieter than deleting, and never in the green of saying yes. */
.button--refuse {
  background: var(--danger-wash);
  border-color: var(--danger-border);
  color: var(--danger);
}

.button--refuse:hover:not([disabled]) {
  background: var(--danger-wash-hover);
  border-color: var(--danger);
}

.button--danger {
  background: transparent;
  border-color: var(--danger);
  color: var(--danger);
}

.button--danger:hover:not([disabled]) {
  background: var(--danger);
  color: var(--accent-text);
}

.card--danger {
  border-color: var(--danger);
}

/* ---------------------------------------------------------------- confirming */

/* The site's own "are you sure", in place of the browser's. No padding on the dialog itself:
   a click on the dialog element then can only be the backdrop, which declines. */
.confirm {
  width: min(28rem, calc(100% - 2 * var(--space-4)));
  padding: 0;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--surface-raised);
  color: var(--ink-body);
  box-shadow: 0 12px 32px rgba(26, 26, 26, 0.18);
}

.confirm::backdrop {
  background: rgba(26, 26, 26, 0.45);
}

.confirm__body {
  margin: 0;
  padding: var(--space-5);
}

.confirm__title {
  margin: 0 0 var(--space-2);
  font-family: var(--font-editorial);
  font-size: var(--text-lg);
  color: var(--ink);
  overflow-wrap: anywhere;
}

.confirm__detail {
  margin: 0;
  font-size: var(--text-base);
}

/* One extra thing to do along with the action, offered as a tickbox. */
.confirm__option {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
  font-size: var(--text-base);
  cursor: pointer;
}

.confirm__option[hidden] {
  display: none;
}

.confirm__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-top: var(--space-5);
}

/* The sentence the readers will actually receive, shown as the thing it is rather than described.
   Nobody should have to guess what their family is about to be sent. */
.quoted-notice {
  margin: var(--space-4) 0;
  padding: var(--space-3) var(--space-4);
  border-left: 2px solid var(--danger);
  background: var(--surface-raised);
  font-family: var(--font-editorial);
  font-size: var(--text-lg);
  color: var(--ink);
}

/* A list of consequences, not of navigation. Bullets would make it look like a menu. */
.plain-list {
  margin: var(--space-3) 0 var(--space-4);
  padding-left: var(--space-4);
  color: var(--ink-body);
}

.plain-list li {
  margin-bottom: var(--space-2);
}

/* ---------------------------------------------------------------- the public site

   The same footer the site has, so an admin can reach any page of it rather than only the front
   page. Duplicated from site.css rather than shared, because the admin pages load app.css alone
   and a third stylesheet for seven rules would cost a request on every screen. */

.site-footer {
  border-top: var(--border);
  padding: var(--space-6) var(--space-4);
  text-align: center;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.site-footer nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  justify-content: center;
  margin-bottom: var(--space-3);
  border: 0;
  padding: 0;
  background: none;
}

.site-footer a {
  color: var(--ink-muted);
  font-size: var(--text-sm);
  letter-spacing: normal;
  text-transform: none;
}

.site-footer a:hover {
  color: var(--ink);
}

/* ---------------------------------------------------------------- touch

   On a screen without a mouse, every control that does something is at least as tall as a
   fingertip. Measured on a phone, Remove was 24px and the rows it sits in are 49px apart, so the
   button to take somebody off a list was less than half the height of the gap around it. It asks
   before acting, which makes a mis-tap recoverable rather than harmless.

   Scoped to a coarse pointer so a mouse keeps the tighter spacing, and limited to controls that
   act: making the navigation and footer links this tall as well would turn the chrome into most
   of a small screen. */
@media (pointer: coarse) {
  button:not(.nav__signout),
  a.button--primary,
  a.button--secondary,
  .link-button {
    min-height: 44px;
  }

  .people__row {
    gap: var(--space-3);
  }

  /* The one on the age confirmation decides whether a writer can be added at all. */
  input[type="checkbox"] {
    width: 20px;
    height: 20px;
  }
}

/* An "i" beside a label, and the panel it opens.

   Positioned against the label row rather than the icon so the panel can be wider than the icon
   and still line up with the field. The row establishes the containing block; the panel is
   absolute inside it.

   It opens three ways, and all three are needed: hover for a mouse, focus-within for a keyboard,
   and aria-expanded for a tap, which produces neither. Relying on hover alone hides the whole
   thing on a phone, which is where somebody is most likely to be stuck for a name. */
.field__label-row {
  display: flex;
  align-items: center;
  /* Enough that the button's own box, which is wider than the circle drawn in it, does not
     reach back over the end of the label and swallow clicks meant for the field. */
  gap: var(--space-3);
  position: relative;
  margin-bottom: var(--space-1);
}

.field__label-row label {
  margin-bottom: 0;
}

.hint {
  display: inline-flex;
}

/* The button is 44px square and invisible; the circle you can see is drawn inside it at 18px.

   Doing it the other way round - an 18px button with the target faked by a transparent overlay -
   makes the control measure 18px to anything that asks, including the test that exists to stop
   controls being too small to tap. The target has to be the real element, and the negative
   margins keep a 44px box from setting the height of a row of 13px text. */
.hint__button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin: -13px;
  padding: 0;
  border: 0;
  background: none;
  cursor: help;
  position: relative;
}

.hint__button::before {
  content: "i";
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: 1px solid var(--rule-strong);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink-muted);
  font-family: var(--font-editorial);
  font-size: var(--text-xs);
  font-style: italic;
  font-weight: 700;
  line-height: 1;
}

.hint__button:hover::before,
.hint__button:focus-visible::before {
  border-color: var(--accent);
  color: var(--accent);
}

/* The global button:focus ring would trace the 44px box rather than the circle, drawing a grey
   rectangle round the icon on every click. It has to be :focus, not :focus-visible: a mouse click
   focuses the button without ever matching :focus-visible, which is exactly the case that showed
   the rectangle. The ring is then put back on the circle for keyboard users only. */
.hint__button:focus {
  outline: none;
}

.hint__button:focus-visible::before {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.hint__panel {
  position: absolute;
  top: calc(100% + var(--space-2));
  left: 0;
  z-index: 20;
  display: none;
  width: min(22rem, calc(100vw - var(--space-5)));
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--surface-raised);
  box-shadow: var(--shadow-soft);
  font-size: var(--text-xs);
  font-weight: 400;
  color: var(--ink-body);
  text-align: left;
}

.field__label-row:hover .hint__panel,
.field__label-row:focus-within .hint__panel,
.hint__button[aria-expanded="true"] + .hint__panel {
  display: block;
}

.hint__heading {
  display: block;
  font-family: var(--font-ui);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: var(--space-2);
}

.hint__list {
  margin: 0 0 var(--space-3);
  padding: 0;
  list-style: none;
  font-family: var(--font-editorial);
  font-size: var(--text-sm);
  columns: 2;
  column-gap: var(--space-4);
}

.hint__list li {
  break-inside: avoid;
  padding: 1px 0;
}

.hint__tip {
  display: block;
  color: var(--ink-muted);
  border-top: var(--border);
  padding-top: var(--space-2);
}

/* One column is easier to read than two narrow ones once the panel is phone-width, and hover
   cannot open it here anyway, so the tap target has to be worth hitting. */
@media (max-width: 30rem) {
  .hint__list {
    columns: 1;
  }

  .hint__panel {
    right: 0;
    width: auto;
  }
}


