/* Subscribe dialog — 2026-09-14. Hand-maintained, not emitted by the
 * pipeline. Pairs with tools/fragments/subscribe-dialog.mjs (the markup) and
 * src/lib/subscribe-dialog.js (the behaviour); imported by the two Research
 * drafts AND, since 2026-09-15, by every article page, whose sheet
 * (blog-post.css) never emitted `type-md-lg`, the newsletter field's pill or
 * the honeypot — so the title, the field and the honeypot are drawn HERE, in
 * the same values blog.css gives them, and the dialog reads the same under
 * either page key. `sd-` prefix.
 *
 * A native <dialog>: closed it generates no box, so the page's height and
 * its resting render are untouched, and open it gives the focus trap and
 * the Escape key for free. The panel is one of this site's own cards — the
 * page surface, the capture's hairline and its 4px corner — with one drop
 * shadow, which is the elevation a surface over the page takes here. Every
 * colour is a token; the backdrop is the one literal, black at 40%, the same
 * in both themes as a scrim always is.
 */

.sd {
  width: min(30rem, calc(100% - 2 * var(--spacing-g2)));
  max-height: calc(100dvh - 2 * var(--spacing-g2));
  margin: auto;
  padding: 0;
  border: 1px solid var(--color-theme-border-02);
  border-radius: var(--radius-xs);
  background: var(--color-theme-bg);
  color: var(--color-theme-text);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.08),
    0 16px 40px -12px rgba(0, 0, 0, 0.3);
  overflow: auto;
}

.sd::backdrop {
  background: rgba(0, 0, 0, 0.4);
}

.sd__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-g1);
  padding: var(--spacing-g2);
}

.sd__close {
  position: absolute;
  top: var(--spacing-g1);
  right: var(--spacing-g1);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 0;
  border-radius: 9999px;
  background: transparent;
  color: var(--color-theme-text-sec);
  cursor: pointer;
}

.sd__close:hover {
  background: var(--color-theme-card-hover-hex);
  color: var(--color-theme-text);
}

.sd__title {
  margin: 0;
  padding-right: 2.5rem;
  /* blog.css's own `type-md-lg`, restated: blog-post.css has no such class. */
  font-size: var(--text-md-lg);
  line-height: var(--leading-snug);
  font-weight: var(--font-weight-normal);
  letter-spacing: var(--tracking-md-lg);
}

.sd__lede {
  margin: 0;
}

.sd__email {
  color: var(--color-theme-text);
}

/* The sections — a small muted name over its rows. The gap between
 * sections is a step up from the gap between rows inside one, which is
 * what makes three names read as three groups rather than six rows with
 * three captions between them. */
.sd__groups {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-g1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.sd__group {
  list-style: none;
}

.sd__group-name {
  display: block;
  padding: 0 0 0.25rem;
}

.sd__topics {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.sd__topic {
  list-style: none;
}

/* The row's inline padding is the hover fill's breathing room and nothing
 * else, so it is paid back by a negative margin: the checkbox sits on the
 * title's own left edge and the section names above it (2026-09-15). */
.sd__topic-label {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-g1);
  margin-inline: calc(-1 * var(--spacing-g1));
  padding: 0.375rem var(--spacing-g1);
  border-radius: var(--radius-xs);
  cursor: pointer;
}

.sd__topic-label:hover {
  background: var(--color-theme-card-hover-hex);
}

.sd__check {
  flex: none;
  width: 1rem;
  height: 1rem;
  margin: 0.3rem 0 0;
  accent-color: var(--color-theme-fg);
  cursor: pointer;
}

/* `Name – description` on one line, wrapping as prose if it must. */
.sd__topic-text {
  min-width: 0;
  color: var(--color-theme-text);
}

.sd__topic-name {
  font-weight: var(--font-weight-medium);
}

.sd__topic-desc {
  font-weight: var(--font-weight-normal);
}

.sd__status {
  margin: 0;
  min-height: 1.5em;
  color: var(--color-theme-text);
}

.sd__status:empty {
  display: none;
}

/* The thank-you panel shown in the form's place after a successful POST. */
.sd__done {
  gap: var(--spacing-g1);
}

/* blog.css's `.btn` carries a size and a padding that blog-post.css's copy
 * of the same rule does not (frozen output for a page with no button on
 * it), so the two are restated here — the token is on both sheets. */
.sd .btn {
  font-size: var(--text-base);
  padding: var(--button-padding-default);
}

.sd__actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--spacing-g1);
  margin-top: var(--spacing-g1);
}

.sd [aria-busy='true'] {
  opacity: 0.6;
  cursor: default;
}

/* Loading the live list: the snapshot's rows stay put and simply dim. */
.sd__topics[aria-busy='true'] {
  opacity: 0.6;
}

/* The dialog's own email field (an article page, whose opener is a bare button). The
 * captured newsletter field's classes draw the pill; this only spaces it. */
.sd__field {
  position: relative;
}

.sd__input {
  /* The captured newsletter field's pill, restated value for value (its
   * classes are blog.css's and the article sheet has none of them). */
  width: 100%;
  padding: 0.56em var(--spacing-g1) 0.58em;
  border: 1px solid var(--color-theme-border-02);
  border-radius: 9999px;
  background: var(--color-theme-card-hex);
  color: var(--color-theme-text);
  font: inherit;
}

.sd__input::placeholder {
  color: var(--color-theme-text-sec);
  opacity: 0.6;
}

.sd__input:hover {
  background: var(--color-theme-card-hover-hex);
}

.sd__input:focus {
  outline: none;
  border-color: var(--color-theme-fg);
  background: var(--color-theme-card-hover-hex);
}

/* The honeypot — newsletter.css's own rule, which the article pages never
 * import. Off-screen, out of the tab order, hidden from assistive tech. */
.sd .newsletter-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
