﻿/* ChairTime — Auth flows (signup wizard, login, account)
   Mobile-first by default, including the folded (~280-340px wide) phone
   case from the App-Client. Breakpoints scale UP from there. Reuses the
   color/font tokens defined in site.css — DO NOT redeclare them here. */

/* ───────────────────────── Auth shell ───────────────────────── */

.auth-page {
  min-height: calc(100vh - 64px);
  padding: 1rem 0 7rem;        /* bottom padding leaves room for sticky CTA */
  position: relative;
}

.auth-shell {
  width: 100%;
  max-width: 420px;
  margin: 0 auto;
  padding: 0 1rem;
}

.auth-card {
  background: var(--color-surface-container-lowest);
  border-radius: 1.25rem;
  padding: 1.5rem 1.25rem;
  box-shadow: 0 24px 64px color-mix(in srgb, var(--color-on-surface) 8%, transparent);
}

/* Folded (very narrow) phone — pull padding in further so it breathes. */
@media (max-width: 340px) {
  .auth-shell { padding: 0 0.6rem; }
  .auth-card  { padding: 1.1rem 0.9rem; border-radius: 1rem; }
}

/* Wider screens — ease the squeeze. */
@media (min-width: 600px) {
  .auth-page  { padding: 2.5rem 0 4rem; }
  .auth-shell { max-width: 480px; }
  .auth-card  { padding: 2rem 1.75rem; border-radius: 1.5rem; }
}

@media (min-width: 1100px) {
  .auth-shell { max-width: 1080px; }
  .auth-card.split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    overflow: hidden;
  }
  .auth-card.split .auth-art {
    display: flex;
    align-items: stretch;
    background: linear-gradient(160deg,
      color-mix(in srgb, var(--color-primary-container) 90%, transparent),
      color-mix(in srgb, var(--color-surface) 70%, var(--color-primary-container)));
  }
}

/* ───────────────────────── Headings + steps ──────────────────── */

.auth-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.7rem;
  border-radius: 9999px;
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.auth-card h1 {
  margin: 0.75rem 0 0.4rem;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.5rem;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--color-on-surface);
}
@media (min-width: 600px) {
  .auth-card h1 { font-size: 1.875rem; }
}

.auth-card .lede {
  margin: 0;
  color: var(--color-on-surface-variant);
  font-size: 0.95rem;
  line-height: 1.5;
}

.auth-progress {
  display: flex;
  gap: 0.4rem;
  margin: 1rem 0 0.25rem;
}
.auth-progress .step {
  flex: 1;
  min-width: 0;
  height: 4px;
  /* Reset the global marketing ".step" card styles (site.css) that otherwise
     inflate these thin progress segments into big padded pills. */
  padding: 0;
  box-shadow: none;
  border-radius: 9999px;
  background: var(--color-surface-container);
}
.auth-progress .step.done    { background: var(--color-primary-dim); }
.auth-progress .step.active  { background: var(--color-primary); }

/* ───────────────────────── Form primitives ──────────────────── */

.field-group {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin-top: 1.25rem;
}

.field-row {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

@media (min-width: 600px) {
  .field-row.two-up {
    flex-direction: row;
    gap: 0.75rem;
  }
  .field-row.two-up > .field { flex: 1; min-width: 0; }
}

.field { display: flex; flex-direction: column; gap: 0.4rem; min-width: 0; }

.field label {
  font-family: "Plus Jakarta Sans", sans-serif;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--color-on-surface-variant);
}

/* An attribute selector matches nothing when the attribute is absent, so
   <input name="x" /> with no type at all fell straight through this list
   and rendered as a raw browser box — half the height of its neighbours.
   Worse, the :focus rule below is NOT type-qualified, so those inputs
   still lit up on focus and read as deliberate rather than broken.
   :not([type]) is the missing case.

   Exclusion — input:not([type="checkbox"]):not([type="radio"]) — would be
   tidier and would also catch any type added later. It can't be used: each
   :not() carries its argument's specificity, so that selector scores
   (0,4,1) and would outrank both `.field input:focus` and
   `.field input.invalid` at (0,2,1), silently killing the focus ring and
   the validation border. Every line below is (0,2,1) on purpose. A new
   input type has to be added here, same as before.

   The .label-row / .proc-option / .proc-toolbar selectors hold plain
   inputs in a grid where .field's column layout can't be used. They're in
   this rule rather than a copy of it so the two can't drift. */
.field input[type="text"],
.field input[type="email"],
.field input[type="tel"],
.field input[type="password"],
.field input[type="number"],
.field input[type="date"],
.field input[type="search"],
.field input:not([type]),
.field select,
.label-row input,
.proc-option input,
.proc-toolbar input,
.proc-toolbar select {
  width: 100%;
  min-height: 48px;        /* hits Apple HIG / Material tap-target floor */
  padding: 0.75rem 0.95rem;
  font-family: "Plus Jakarta Sans", sans-serif;
  font-size: 1rem;
  color: var(--color-on-surface);
  background: var(--color-surface-container-low);
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.85rem;
  outline: none;
  transition: border-color 120ms ease, box-shadow 120ms ease, background 120ms ease;
  -webkit-appearance: none;
  appearance: none;
  box-sizing: border-box;
}
.field input:focus,
.field select:focus,
.label-row input:focus,
.proc-option input:focus,
.proc-toolbar input:focus,
.proc-toolbar select:focus {
  border-color: var(--color-primary);
  background: var(--color-surface-container-lowest);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 22%, transparent);
}
.field .helper {
  font-size: 0.78rem;
  color: var(--color-on-surface-variant);
}
.field .error {
  font-size: 0.78rem;
  color: var(--color-error);
}
.field input.invalid,
.field select.invalid {
  border-color: var(--color-error);
}

.field-checkbox {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  font-size: 0.88rem;
  line-height: 1.4;
  color: var(--color-on-surface-variant);
}
.field-checkbox input[type="checkbox"] {
  width: 20px;
  height: 20px;
  margin-top: 0.15rem;
  accent-color: var(--color-primary);
  flex: 0 0 auto;
}

.alert-error {
  margin-top: 1rem;
  padding: 0.7rem 0.9rem;
  background: color-mix(in srgb, var(--color-error-container) 80%, transparent);
  color: var(--color-on-error-container);
  border-radius: 0.85rem;
  font-size: 0.88rem;
  line-height: 1.4;
}

.alert-info {
  margin-top: 1rem;
  padding: 0.7rem 0.9rem;
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
  border-radius: 0.85rem;
  font-size: 0.88rem;
  line-height: 1.4;
}

/* ───────────────────────── Buttons ─────────────────────────── */

.btn-block {
  width: 100%;
  justify-content: center;
  min-height: 52px;
  padding: 0.95rem 1.4rem;
}

.btn-secondary {
  background: var(--color-surface-container);
  color: var(--color-on-surface);
}
.btn-secondary:hover {
  background: var(--color-surface-container-high);
}

.btn[disabled],
.btn[aria-disabled="true"] {
  opacity: 0.6;
  cursor: not-allowed;
  filter: grayscale(0.2);
}

.divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1.25rem 0;
  color: var(--color-on-surface-variant);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.divider::before,
.divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--color-outline-variant);
}

.btn-google {
  width: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: 52px;
  border-radius: 9999px;
  background: var(--color-surface-container-lowest);
  color: var(--color-on-surface);
  border: 1px solid var(--color-outline-variant);
  font-family: "Plus Jakarta Sans", sans-serif;
  font-weight: 600;
  font-size: 0.95rem;
  cursor: pointer;
  text-decoration: none;
  transition: background 120ms ease;
}
.btn-google:hover { background: var(--color-surface-container-low); }
.btn-google[aria-disabled="true"] {
  cursor: not-allowed;
  color: var(--color-on-surface-variant);
}
.btn-google .g-mark {
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 0.95rem;
  border-radius: 9999px;
  background: linear-gradient(135deg, #4285f4, #34a853 50%, #fbbc04 75%, #ea4335);
  color: white;
}

/* ───────────────────────── Footer link row ─────────────────── */

.auth-foot {
  margin-top: 1.25rem;
  text-align: center;
  font-size: 0.9rem;
  color: var(--color-on-surface-variant);
}
.auth-foot a { font-weight: 600; }

/* ───────────────────────── OTP input ─────────────────────────
   Single input box with autocomplete="one-time-code" — research-backed
   over multi-cell inputs because mobile browsers autofill the entire
   code into a single field from the SMS notification banner. */

.otp-input {
  width: 100%;
  min-height: 64px;
  padding: 0.9rem 1rem;
  font-family: "Manrope", monospace, sans-serif;
  font-size: 2rem;
  font-weight: 800;
  letter-spacing: 0.45rem;
  text-align: center;
  color: var(--color-on-surface);
  background: var(--color-surface-container-low);
  border: 2px solid var(--color-outline-variant);
  border-radius: 1rem;
  outline: none;
  transition: border-color 120ms ease, box-shadow 120ms ease;
  box-sizing: border-box;
}
.otp-input:focus {
  border-color: var(--color-primary);
  background: var(--color-surface-container-lowest);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 22%, transparent);
}

.resend-row {
  margin-top: 0.9rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.85rem;
  color: var(--color-on-surface-variant);
}
.resend-row button {
  background: transparent;
  border: none;
  color: var(--color-primary);
  font-weight: 600;
  cursor: pointer;
  font-size: 0.85rem;
  font-family: inherit;
}
.resend-row button[disabled] {
  color: var(--color-on-surface-variant);
  cursor: not-allowed;
}

/* ───────────────────────── Pricing / plans grid ─────────────── */

.pricing-hero {
  text-align: center;
  padding: 2.5rem 1rem 1.5rem;
}
.pricing-hero h1 {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: clamp(1.875rem, 5vw, 3rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0.75rem 0 0.5rem;
}
.pricing-hero p {
  margin: 0 auto;
  max-width: 56ch;
  color: var(--color-on-surface-variant);
  font-size: 1rem;
}

.cadence-toggle {
  display: inline-flex;
  margin: 1.5rem auto 0;
  background: var(--color-surface-container);
  padding: 0.3rem;
  border-radius: 9999px;
}
.cadence-toggle button {
  padding: 0.55rem 1rem;
  border: none;
  border-radius: 9999px;
  background: transparent;
  font-family: "Plus Jakarta Sans", sans-serif;
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--color-on-surface-variant);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.cadence-toggle button.active {
  background: var(--color-surface-container-lowest);
  color: var(--color-on-surface);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--color-on-surface) 8%, transparent);
}
.cadence-toggle .save-pill {
  margin-left: 0.4rem;
  padding: 0.1rem 0.45rem;
  border-radius: 9999px;
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
  font-size: 0.65rem;
  font-weight: 700;
}

.plan-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  max-width: 1180px;
  margin: 1.5rem auto 0;
  padding: 0 1rem;
}
@media (min-width: 720px) {
  .plan-grid { grid-template-columns: repeat(2, 1fr); padding: 0 1.5rem; }
}
@media (min-width: 1000px) {
  .plan-grid { grid-template-columns: repeat(3, 1fr); }
}

.plan-card {
  position: relative;
  background: var(--color-surface-container-lowest);
  border-radius: 1.5rem;
  padding: 1.5rem 1.25rem 1.75rem;
  border: 1px solid var(--color-outline-variant);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  transition: transform 200ms ease, box-shadow 200ms ease, border-color 200ms ease;
}
.plan-card:hover { transform: translateY(-2px); }
.plan-card.popular {
  border-color: var(--color-primary);
  box-shadow: 0 24px 56px color-mix(in srgb, var(--color-primary) 18%, transparent);
}
.plan-badge {
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  padding: 0.25rem 0.7rem;
  background: var(--color-primary);
  color: var(--color-on-primary);
  border-radius: 9999px;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
}
.plan-name {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.25rem;
  letter-spacing: -0.01em;
  margin: 0;
}
.plan-desc {
  margin: 0;
  font-size: 0.9rem;
  color: var(--color-on-surface-variant);
  line-height: 1.5;
}
.plan-price {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  flex-wrap: wrap;
}
.plan-price .amount {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 2.25rem;
  letter-spacing: -0.02em;
  color: var(--color-on-surface);
}
.plan-price .per {
  font-size: 0.85rem;
  color: var(--color-on-surface-variant);
}
.plan-price .yearly-note {
  width: 100%;
  font-size: 0.78rem;
  color: var(--color-on-surface-variant);
}
.plan-features {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.plan-features li {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-size: 0.92rem;
  color: var(--color-on-surface);
}
.plan-features li.muted { color: var(--color-on-surface-variant); }
.plan-features li .material-symbols-outlined {
  font-size: 18px;
  margin-top: 0.1rem;
  color: var(--color-primary);
}
.plan-features li.muted .material-symbols-outlined {
  color: var(--color-outline-variant);
}

.plan-cta {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: auto;
}
.plan-cta .trial-link {
  text-align: center;
  font-size: 0.85rem;
  color: var(--color-primary);
  font-weight: 600;
  background: transparent;
  border: none;
  cursor: pointer;
  font-family: inherit;
}

/* Trust strip + testimonial */

.trust-strip {
  margin: 2rem auto 1rem;
  max-width: 720px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  padding: 1.25rem 1rem;
  text-align: center;
  color: var(--color-on-surface-variant);
  font-size: 0.85rem;
}
.trust-strip .badges {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
}
.trust-strip .badges span {
  padding: 0.3rem 0.7rem;
  border-radius: 9999px;
  background: var(--color-surface-container);
  color: var(--color-on-surface);
  font-weight: 600;
  font-size: 0.75rem;
}
.testimonial {
  max-width: 640px;
  margin: 1rem auto 2rem;
  padding: 1.25rem;
  background: var(--color-surface-container-lowest);
  border-radius: 1.25rem;
  text-align: center;
}
.testimonial blockquote {
  margin: 0 0 0.75rem;
  font-size: 1rem;
  line-height: 1.55;
  color: var(--color-on-surface);
  font-style: italic;
}
.testimonial cite {
  font-size: 0.85rem;
  color: var(--color-on-surface-variant);
  font-style: normal;
}

/* ───────────────────────── Sticky CTA bar (mobile) ────────── */

.sticky-cta {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  background: color-mix(in srgb, var(--color-surface) 92%, transparent);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  padding: 0.85rem 1rem calc(0.85rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--color-outline-variant);
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  align-items: stretch;
}
.sticky-cta .micro {
  font-size: 0.78rem;
  color: var(--color-on-surface-variant);
  text-align: center;
}
@media (min-width: 720px) {
  .sticky-cta { position: static; background: transparent; backdrop-filter: none; -webkit-backdrop-filter: none; padding: 1rem 0; border-top: none; }
}

/* ───────────────────────── Checkout summary ──────────────── */

.checkout-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}
@media (min-width: 900px) {
  .checkout-grid { grid-template-columns: 1.4fr 1fr; gap: 1.75rem; }
}
.summary-card {
  background: var(--color-surface-container-low);
  border-radius: 1.25rem;
  padding: 1.25rem;
}
.summary-card h2 {
  margin: 0 0 0.75rem;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.1rem;
  letter-spacing: -0.01em;
}
.summary-row {
  display: flex;
  justify-content: space-between;
  padding: 0.55rem 0;
  font-size: 0.92rem;
  color: var(--color-on-surface);
  border-bottom: 1px dashed var(--color-outline-variant);
}
.summary-row:last-of-type { border-bottom: none; }
.summary-row.muted { color: var(--color-on-surface-variant); }
.summary-row.total {
  font-weight: 700;
  font-size: 1.05rem;
  border-bottom: none;
  padding-top: 0.85rem;
}
.coupon-toggle {
  margin-top: 0.5rem;
  background: transparent;
  border: none;
  color: var(--color-primary);
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
  padding: 0;
  font-family: inherit;
}
.coupon-collapsed { display: none; }
.coupon-collapsed.open { display: flex; flex-direction: column; gap: 0.5rem; margin-top: 0.6rem; }

/* ───────────────────────── Account page ──────────────────── */

.account-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  max-width: 880px;
  margin: 1.5rem auto 4rem;
  padding: 0 1rem;
}
@media (min-width: 720px) {
  .account-grid { grid-template-columns: 1.2fr 1fr; }
}

.account-card {
  background: var(--color-surface-container-lowest);
  border-radius: 1.25rem;
  padding: 1.5rem 1.25rem;
  box-shadow: 0 16px 40px color-mix(in srgb, var(--color-on-surface) 6%, transparent);
}
.account-card h2 {
  margin: 0 0 0.75rem;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.15rem;
  letter-spacing: -0.01em;
}
.account-card .row {
  display: flex;
  justify-content: space-between;
  padding: 0.55rem 0;
  font-size: 0.95rem;
  border-bottom: 1px dashed var(--color-outline-variant);
  gap: 0.75rem;
}
.account-card .row:last-of-type { border-bottom: none; }
.account-card .row .label { color: var(--color-on-surface-variant); }
.account-card .badges { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.5rem; }
.account-card .badges span {
  padding: 0.25rem 0.6rem;
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
  border-radius: 9999px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* Read-only invoice history inside the Billing card. Rows reuse the
   dashed .row rhythm; the status pill mirrors the .badges pill at a
   smaller scale so the card reads as one family. */
.account-card .invoice-history {
  margin-top: 1.1rem;
  border-top: 1px solid var(--color-outline-variant);
  padding-top: 0.85rem;
}
.account-card .invoice-history h3 {
  margin: 0 0 0.25rem;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-on-surface-variant);
}
.account-card .invoice-history .row { font-size: 0.9rem; }
.account-card .invoice-history .inv-date {
  display: block;
  font-size: 0.75rem;
  color: var(--color-outline);
}
.account-card .invoice-history .inv-amount {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-variant-numeric: tabular-nums;
}
.account-card .invoice-history .inv-void {
  text-decoration: line-through;
  color: var(--color-outline);
}
.account-card .invoice-history .inv-status {
  padding: 0.15rem 0.5rem;
  border-radius: 9999px;
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.account-card .invoice-history .inv-status.paid {
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
}
.account-card .invoice-history .inv-status.pending {
  background: var(--color-secondary-container);
  color: var(--color-on-secondary-container);
}
.account-card .invoice-history .inv-status.void {
  background: var(--color-surface-container-high);
  color: var(--color-on-surface-variant);
}

/* ───────────────────────── Billing page ──────────────────── */

/* Full-width cards inside the 2-col account grid. */
@media (min-width: 720px) {
  .account-grid .span-2 { grid-column: 1 / -1; }
}

/* three-up field row (exp month / year / cvc) */
@media (min-width: 520px) {
  .field-row.three-up { display: flex; gap: 0.75rem; }
  .field-row.three-up > .field { flex: 1; min-width: 0; }
}

/* Saved cards */
.card-list { display: flex; flex-direction: column; gap: 0.6rem; margin-bottom: 1.1rem; }
.pay-card {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.8rem 0.95rem;
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.9rem;
  background: var(--color-surface-container-lowest);
}
.pay-card-icon { font-size: 26px; color: var(--color-primary); flex: none; }
.pay-card-main { flex: 1; min-width: 0; }
.pay-card-brand { font-weight: 700; display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.pay-card-dots {
  font-variant-numeric: tabular-nums;
  color: var(--color-on-surface-variant);
  font-weight: 600;
  letter-spacing: 0.05em;
}
.pay-card-default {
  padding: 0.12rem 0.5rem;
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
  border-radius: 9999px;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.pay-card-expired {
  padding: 0.12rem 0.5rem;
  background: color-mix(in srgb, var(--color-error, #b3261e) 14%, transparent);
  color: var(--color-error, #b3261e);
  border-radius: 9999px;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.pay-card.is-expired {
  border-color: color-mix(in srgb, var(--color-error, #b3261e) 40%, var(--color-outline-variant));
}
.pay-card .inv-date { font-size: 0.78rem; color: var(--color-outline); margin-top: 0.15rem; }
.pay-card .inv-date.expired { color: var(--color-error, #b3261e); font-weight: 600; }
.pay-card-actions { display: flex; align-items: center; gap: 0.4rem; flex: none; }
.pay-card-actions form { margin: 0; }
.btn-icon { padding: 0.5rem; line-height: 0; }
.btn-icon .material-symbols-outlined { font-size: 18px; }

/* Add-card modal (native <dialog>) */
.modal {
  border: none;
  border-radius: 1.1rem;
  padding: 0;
  width: min(460px, calc(100vw - 2rem));
  background: var(--color-surface-container-lowest);
  color: var(--color-on-surface);
  box-shadow: 0 30px 70px color-mix(in srgb, var(--color-on-surface) 28%, transparent);
}
.modal::backdrop {
  background: color-mix(in srgb, var(--color-on-surface) 45%, transparent);
  backdrop-filter: blur(2px);
}
.modal[open] { animation: modal-in 0.16s ease-out; }
@keyframes modal-in {
  from { opacity: 0; transform: translateY(6px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
.modal-inner { padding: 1.5rem; }
.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1rem;
}
.modal-head h3 {
  margin: 0;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.15rem;
  letter-spacing: -0.01em;
}
.modal-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: none;
  border-radius: 9999px;
  background: transparent;
  color: var(--color-on-surface-variant);
  cursor: pointer;
}
.modal-close:hover { background: var(--color-surface-container); color: var(--color-on-surface); }
.modal-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.75rem; }

.add-card-form { display: flex; flex-direction: column; gap: 0.25rem; }
.add-card-form .card-check {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  color: var(--color-on-surface-variant);
}
.add-card-form .card-check input { accent-color: var(--color-primary); }

/* Checkout: "no card on file" prompt */
.no-card-note { text-align: center; padding: 0.75rem 0 0.25rem; }
.no-card-note p { margin: 0 0 0.9rem; color: var(--color-on-surface-variant); }

/* Billing General / Invoices tab bar (reuses .pay-tab pills). */
.billing-tabs {
  display: flex;
  gap: 0.4rem;
  max-width: 880px;
  margin: 0.5rem auto 1rem;
  padding: 0 1rem;
}
.billing-tabs .pay-tab { display: inline-flex; align-items: center; gap: 0.35rem; }
.billing-tabs .pay-tab .material-symbols-outlined { font-size: 18px; }

/* Checkout summary: the period a prorated charge covers. */
.charge-period { display: block; font-size: 0.72rem; color: var(--color-outline); font-weight: 400; margin-top: 0.1rem; }

/* Checkout downgrade explanation (replaces the payment method for downgrades). */
.downgrade-note {
  display: flex;
  gap: 0.85rem;
  align-items: flex-start;
  padding: 1.1rem 1.15rem;
  border-radius: 1rem;
  background: var(--color-surface-container);
  border: 1px solid var(--color-outline-variant);
}
.downgrade-note > .material-symbols-outlined { color: var(--color-primary); flex: none; font-size: 24px; }
.downgrade-note p { margin: 0; color: var(--color-on-surface-variant); line-height: 1.5; }

/* Checkout authorize block (initials + acceptance + pay), in the summary card. */
.authorize-block { margin-top: 1rem; }
.authorize-block .field { margin-bottom: 0.4rem; }
.authorize-text { font-size: 0.78rem; color: var(--color-on-surface-variant); line-height: 1.45; margin: 0.5rem 0 0.9rem; }

/* Pending plan change (downgrade / cancellation) banner — deliberately loud. */
.pending-change-banner {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.9rem 1.1rem;
  border-radius: 1rem;
  background: var(--color-secondary-container);
  color: var(--color-on-secondary-container);
  border: 1px solid color-mix(in srgb, var(--color-primary) 32%, transparent);
}
.pending-change-banner > .material-symbols-outlined { color: var(--color-primary); flex: none; }
.pending-change-text { flex: 1; display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.pending-change-text span { font-size: 0.86rem; opacity: 0.9; }
.pending-change-banner form { flex: none; }
@media (max-width: 560px) {
  .pending-change-banner { flex-wrap: wrap; }
  .pending-change-banner form, .pending-change-banner form .btn { width: 100%; }
}

/* Security reassurance line */
.security-note {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin: 1.1rem 0 0;
  padding: 0.75rem 0.9rem;
  border-radius: 0.75rem;
  background: var(--color-surface-container);
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--color-on-surface-variant);
}
.security-note .material-symbols-outlined {
  font-size: 18px;
  color: var(--color-primary);
  flex: none;
  margin-top: 1px;
}

/* Invoice table with per-row PDF download */
.invoice-table { display: flex; flex-direction: column; }
.invoice-row {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  align-items: center;
  gap: 0.75rem;
  padding: 0.7rem 0;
  border-bottom: 1px dashed var(--color-outline-variant);
}
.invoice-row:last-child { border-bottom: none; }
.invoice-num { font-weight: 600; }
.invoice-num .inv-date { display: block; font-size: 0.75rem; color: var(--color-outline); font-weight: 400; }
.invoice-amt { font-variant-numeric: tabular-nums; font-weight: 700; }
.invoice-amt.inv-void { text-decoration: line-through; color: var(--color-outline); }
.invoice-row .inv-status {
  padding: 0.15rem 0.5rem;
  border-radius: 9999px;
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.invoice-row .inv-status.paid { background: var(--color-primary-container); color: var(--color-on-primary-container); }
.invoice-row .inv-status.pending { background: var(--color-secondary-container); color: var(--color-on-secondary-container); }
.invoice-row .inv-status.void { background: var(--color-surface-container-high); color: var(--color-on-surface-variant); }
.invoice-actions { display: flex; align-items: center; gap: 0.4rem; }
.invoice-actions form { margin: 0; }
.btn-pdf {
  padding: 0.4rem 0.7rem;
  font-size: 0.82rem;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  white-space: nowrap;
}
.btn-pdf .material-symbols-outlined { font-size: 16px; }
.btn-pay { padding: 0.4rem 0.8rem; font-size: 0.82rem; white-space: nowrap; }

@media (max-width: 520px) {
  .invoice-row { grid-template-columns: 1fr auto; row-gap: 0.35rem; }
  .invoice-row .invoice-actions { grid-column: 2; }
}

/* Account credit */
.credit-balance { display: flex; align-items: baseline; gap: 0.5rem; }
.credit-balance-amt {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 2rem;
  letter-spacing: -0.02em;
  color: var(--color-primary);
  font-variant-numeric: tabular-nums;
}
.credit-balance-label { font-size: 0.85rem; color: var(--color-on-surface-variant); }
.credit-ledger { display: flex; flex-direction: column; border-top: 1px solid var(--color-outline-variant); }
.credit-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0;
  border-bottom: 1px dashed var(--color-outline-variant);
}
.credit-row:last-child { border-bottom: none; }
.credit-row-main { display: flex; flex-direction: column; min-width: 0; }
.credit-row-type { font-weight: 600; font-size: 0.92rem; }
.credit-row-main .inv-date { font-size: 0.75rem; color: var(--color-outline); }
.credit-row-amt { font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
.credit-row-amt.added { color: var(--color-primary); }
.credit-row-amt.used { color: var(--color-on-surface-variant); }

/* ── /pay section ──────────────────────────────────────────────────
   Same card family as /Account; only the section chrome (tabs, payday
   pill, money emphasis) is new. */
.pay-head {
  max-width: 880px;
  margin: 2rem auto 0;
  padding: 0 1rem;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
.pay-head h1 {
  margin: 0;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
/*  Pill tab bar. Nothing renders it right now: /Pay and /Pay/Reports carried
    one until the sidebar already listed both destinations under Money, which
    made it a second copy of a menu the reader had just used. Kept because the
    .billing-tabs rules above lean on .pay-tab. */
.pay-tabs { display: flex; gap: 0.35rem; }
.pay-tab {
  padding: 0.4rem 0.9rem;
  border-radius: 9999px;
  font-size: 0.85rem;
  font-weight: 700;
  text-decoration: none;
  color: var(--color-on-surface-variant);
  background: var(--color-surface-container);
}
.pay-tab.active {
  background: var(--color-primary);
  color: var(--color-on-primary);
}
.pay-grid { margin-top: 0; }
.pay-wrap {
  max-width: 880px;
  margin: 1.5rem auto 4rem;
  padding: 0 1rem;
}
.pay-clinic-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  /* The h2's own bottom margin is zeroed above so the row aligns, which
     left the export buttons resting on the border of whatever box comes
     next. The head owns the gap instead. */
  margin-bottom: 0.9rem;
}
.pay-clinic-head h2 { margin-bottom: 0; }
.payday-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.6rem;
  background: var(--color-secondary-container);
  color: var(--color-on-secondary-container);
  border-radius: 9999px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
}
.payday-pill .material-symbols-outlined { font-size: 14px; }
.pay-summary {
  margin: 0.35rem 0 0.5rem;
  font-size: 0.8rem;
  color: var(--color-on-surface-variant);
}
.pay-section {
  margin: 0.9rem 0 0.1rem;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-on-surface-variant);
}
.account-card .money { font-variant-numeric: tabular-nums; font-weight: 600; }
.account-card .money.earned { color: var(--color-primary); font-weight: 800; }
.muted-note { margin: 0; color: var(--color-on-surface-variant); font-size: 0.9rem; }

/* ── settings rail ─────────────────────────────────────────────────
   The shared shell for /Account/* and /Billing/*, which are one section
   with five panes (see Pages/Shared/_SettingsNav.cshtml).

   The rail is deliberately QUIET — text links with a hairline marker,
   not pills. There is already a primary sidebar three inches to the
   left, and two loud vertical navs side by side read as two apps. This
   one has to look like an index inside the page it belongs to. */
.settings-wrap {
  display: grid;
  /* The pane is capped rather than fluid. Settings are forms and
     label→value rows: at 1400px the pane came out 784px and split into
     two columns of ~416px, which is where the profile form's side-by-side
     fields turn into 190px stubs — and on a 1920px screen a fluid pane
     would run a 1400px line between a label and its value. 48rem is the
     width these read at, whatever the screen does. */
  grid-template-columns: 12.5rem minmax(0, 48rem);
  gap: 2rem;
  align-items: start;
  margin: 1.5rem 0 4rem;
}
.settings-nav {
  position: sticky;
  top: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}
.settings-link {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.7rem;
  border-radius: 0.6rem;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--color-on-surface-variant);
  text-decoration: none;
  white-space: nowrap;
}
.settings-link .material-symbols-outlined { font-size: 19px; opacity: 0.8; }
.settings-link:hover {
  background: var(--color-surface-container-low);
  color: var(--color-on-surface);
}
/* Inset rule rather than a border, so the marker can't change the box
   and shunt every label a pixel sideways on selection. */
.settings-link.active {
  background: var(--color-surface-container);
  color: var(--color-on-surface);
  font-weight: 700;
  box-shadow: inset 3px 0 0 var(--color-primary);
}
.settings-link.active .material-symbols-outlined { opacity: 1; color: var(--color-primary); }

/* Group heading inside a section rail — same job as .side-eyebrow in the
   app sidebar, and deliberately the same voice, so the two vertical navs
   on screen read as one system. First one loses its top margin: a rail
   that opens with a gap looks detached from the heading above it. */
.settings-eyebrow {
  margin: 1.1rem 0 0.3rem;
  padding: 0 0.7rem;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-on-surface-variant);
  opacity: 0.75;
}
.settings-eyebrow:first-child { margin-top: 0; }

/* The rail items on /clinics are the user's own clinic names, not five
   fixed pane labels, so two things the fixed rails never needed:

   1. The label has to be able to run out of room. "Smile Dental — Main St"
      is a perfectly ordinary clinic name and the rail is 200px wide; the
      nowrap on .settings-link would push it under the pane. It truncates
      instead, and the full name is the page title one click away.
   2. A trailing marker for the default clinic, which has to sit at the
      right edge whatever the label does — hence flex: none on the mark and
      flex: 1 on the label rather than letting either size to content. */
.settings-link-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Scoped under .settings-link so it outranks that rail's blanket
   `.settings-link .material-symbols-outlined { font-size: 19px }` — at
   19px the marker read as a second icon rather than a state. */
.settings-link .settings-link-mark {
  flex: none;
  /* Optically smaller than the leading icon: it's a state marker, not a
     second piece of navigation, and at 19px it competed with the name. */
  font-size: 15px;
  color: var(--color-primary);
  font-variation-settings: 'FILL' 1;
}

/* Separates the clinics from "Add a clinic". The clinics are places you
   go; adding one is something you do, and without the rule it reads as a
   sixth clinic called "Add a clinic". Inset to the label column so it
   lines up with the text rather than the item's hover box. */
.settings-divider {
  display: block;
  height: 1px;
  margin: 0.5rem 0.7rem;
  background: var(--color-outline-variant);
}

/* ── /clinics: the rail with a second level ───────────────────────
   The only rail in the app that nests. Its top level is the user's
   clinics; the one they're inside opens to that clinic's three panes.

   Two levels in one rail rather than a rail plus a tab strip above the
   pane: the app sidebar is already on screen, and a horizontal band next
   to it would be a second navigation SYSTEM rather than a second level
   of this one. */

/* A shade wider than the fixed rails — the child rows start where the
   parent's LABEL starts, and 12.5rem doesn't have that indent to spare. */
.settings-wrap:has(.clinics-nav) { grid-template-columns: 14rem minmax(0, 48rem); }

/* Parent row. Being "open" is not being "active": the clinic you're
   inside is context, the pane you're on is location. So this gets weight
   and full-strength text and nothing else — the fill and the inset rule
   stay reserved for the child that is actually the current page. Two
   identical highlights stacked read as a bug, not as a hierarchy. */
.clinic-link.open {
  color: var(--color-on-surface);
  font-weight: 700;
}
.clinic-link.open .material-symbols-outlined { color: var(--color-primary); opacity: 1; }

.clinic-sections {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  /* Hairline down the child group: it ties three rows into one block and
     marks where the level starts, which indentation alone does weakly at
     this row height. Sits under the parent's icon, so the children hang
     off the parent rather than floating beside it. */
  /* 1.2rem + 1px border + 0.55rem padding lands the child's own text
     padding exactly on the parent's label — measured, not guessed. */
  margin: 0.15rem 0 0.35rem 1.2rem;
  padding-left: 0.55rem;
  border-left: 1px solid var(--color-outline-variant);
}

/* Child row. No icon at all — dropping it is a stronger level cue than
   any amount of indent, and it buys back the width the indent costs. */
.clinic-section {
  padding-top: 0.4rem;
  padding-bottom: 0.4rem;
  font-size: 0.85rem;
  font-weight: 600;
}
.clinic-section.active {
  background: var(--color-surface-container);
  color: var(--color-on-surface);
  font-weight: 700;
  box-shadow: inset 3px 0 0 var(--color-primary);
}

/* The wrapper owns the width and the gutter; the grid inside fills it
   rather than re-centring at its own max-width. */
.settings-body { min-width: 0; }
.settings-body .account-grid {
  max-width: none;
  margin: 0;
  padding: 0;
}
.settings-body .alert-info,
.settings-body .alert-error { margin: 0 0 1rem; }

/* Always one column. .account-grid goes two-up at a 720px VIEWPORT,
   which was right when it owned the whole content rail — but the pane is
   capped at 48rem now, and two columns inside that is narrower than any
   of these forms want. Settings read top to bottom; nothing here is a
   dashboard. */
.settings-grid { grid-template-columns: 1fr; }
.settings-grid > .span-2 { grid-column: auto; }

@media (max-width: 900px) {
  /* Under the header instead of beside it, scrolling sideways — a rail
     stacked as a block would push the pane a screen down. */
  .settings-wrap { grid-template-columns: 1fr; gap: 1.1rem; }
  .settings-nav {
    position: static;
    flex-direction: row;
    gap: 0.35rem;
    overflow-x: auto;
    padding-bottom: 0.3rem;
    scrollbar-width: none;
  }
  .settings-nav::-webkit-scrollbar { display: none; }
  .settings-link { flex: none; }
  /* Laid out sideways the group headings become chips you can't click.
     The order still carries the grouping. */
  .settings-eyebrow { display: none; }
  /* Horizontal, the inset rule would sit on the left edge of a chip and
     read as debris. The fill carries the state on its own. */
  .settings-link.active { box-shadow: none; }
  /* Sideways the separator has to turn with the rail — a 1px-tall rule
     between two chips in a row is invisible. */
  .settings-divider {
    flex: none;
    width: 1px;
    height: auto;
    align-self: stretch;
    margin: 0.25rem 0.2rem;
  }

  /*  An accordion can't lie on its side, so the two levels become bands,
      top to bottom: the clinics, then the open clinic's panes, then a
      rule, then Add. Order does the arranging — in the DOM the sections
      sit inside their clinic, halfway up the list.

      Wrapping rather than the sideways scroll the fixed rails use: those
      have five items that fit, this has a clinic count that doesn't, and
      a chip scrolled out of sight in a list of YOUR OWN clinics reads as
      a missing clinic. */
  .clinics-nav { flex-wrap: wrap; overflow-x: visible; }
  .clinics-nav > .settings-link { order: 0; }
  .clinic-sections {
    order: 1;
    flex-basis: 100%;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin: 0.1rem 0 0;
    padding-left: 0;
    border-left: none;
  }
  .clinic-section { flex: none; }
  /* Same reason the parent rail drops it sideways: an inset rule on the
     left edge of a chip reads as debris. */
  .clinic-section.active { box-shadow: none; }
  /* Stacked, the divider goes back to being a horizontal rule — it is
     separating bands now, not neighbours in a row. */
  .clinics-nav > .settings-divider {
    order: 2;
    flex-basis: 100%;
    width: auto;
    height: 1px;
    align-self: auto;
    margin: 0.45rem 0 0.35rem;
  }
  /* Scoped to a child of the rail so it outranks the blanket
     `.clinics-nav > .settings-link { order: 0 }` above — otherwise Add
     stays up in the clinics band. */
  .clinics-nav > .clinic-add { order: 3; }
  /* The width bump is a desktop grid concern; stacked there is no rail
     column to widen. */
  .settings-wrap:has(.clinics-nav) { grid-template-columns: 1fr; }
}

/* ── report style / palette pickers ───────────────────────────────
   A settings page for the look of a document has to show the document.
   The thumbnails are CSS miniatures of the real layouts — a band, three
   rows, a totals bar — because three paragraphs of prose describing
   "tighter rows" is not a choice anyone can make. */
.settings-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1.25rem;
}

.style-picker { display: grid; gap: 0.6rem; }
@media (min-width: 620px) {
  .style-picker { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.style-option {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 0.75rem;
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.9rem;
  cursor: pointer;
  background: var(--color-surface-container-lowest);
}
.style-option:hover { border-color: var(--color-outline); }
.style-option.active {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 1px var(--color-primary);
}
.style-option input { position: absolute; opacity: 0; pointer-events: none; }
.style-option-body { display: flex; flex-direction: column; gap: 0.15rem; }
.style-option-title {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 700;
  font-size: 0.9rem;
}
.style-default {
  padding: 0.1rem 0.4rem;
  border-radius: 999px;
  background: var(--color-surface-container);
  color: var(--color-on-surface-variant);
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.style-option-sub { font-size: 0.76rem; line-height: 1.4; color: var(--color-on-surface-variant); }

/* The miniature. Aspect-ratio keeps it page-shaped at any width. */
.style-thumb {
  display: flex;
  flex-direction: column;
  gap: 3px;
  aspect-ratio: 5 / 4;
  padding: 8px;
  border-radius: 0.5rem;
  background: #fff;
  border: 1px solid var(--color-outline-variant);
  overflow: hidden;
}
.style-thumb span { display: block; border-radius: 2px; }
.st-title { height: 7px; width: 55%; background: var(--color-primary); }
.st-strip { height: 13px; background: color-mix(in srgb, var(--color-primary) 14%, #fff); border: 1px solid color-mix(in srgb, var(--color-primary) 30%, #fff); }
.st-row   { height: 5px; background: #e8e8e8; }
.st-total { height: 6px; background: color-mix(in srgb, var(--color-primary) 28%, #fff); margin-top: auto; }

/* Compact: no cover title, rows packed tighter, more of them fit. */
.style-thumb-compact { gap: 2px; }
.style-thumb-compact .st-title { display: none; }
.style-thumb-compact .st-row { height: 4px; }

/* Statement: the totals become a filled band and headings get a rule. */
.style-thumb-statement .st-title { width: 35%; background: var(--color-primary); }
.style-thumb-statement .st-strip {
  height: 18px;
  background: var(--color-primary);
  border-color: var(--color-primary);
}
.style-thumb-statement .st-row:nth-of-type(even) { background: #f2f2f2; }
.style-thumb-statement .st-total { background: var(--color-primary); }

.palette-picker { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.palette-option {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.7rem 0.45rem 0.5rem;
  border: 1px solid var(--color-outline-variant);
  border-radius: 999px;
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 600;
}
.palette-option:hover { border-color: var(--color-outline); }
.palette-option.active {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 1px var(--color-primary);
}
.palette-option input { position: absolute; opacity: 0; pointer-events: none; }
/* Three swatches, not one: a palette is a relationship between an accent,
   its deep tone and its tint, and a single dot hides two thirds of it. */
.palette-chips { display: inline-flex; }
.palette-chips span {
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--color-on-surface) 12%, transparent);
}
.palette-chips span + span { margin-left: -0.3rem; }

/* Sits outside the settings form (so its click can't submit it), which
   also means it gets no help from the grid's gap. */
.preview-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}
.preview-card-main { min-width: 0; flex: 1 1 18rem; }
.preview-card h2 { margin-bottom: 0.3rem; }

.toggle-list { display: flex; flex-direction: column; }
.toggle-row {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  padding: 0.6rem 0;
  border-bottom: 1px dashed var(--color-outline-variant);
  cursor: pointer;
}
.toggle-row:last-child { border-bottom: none; }
.toggle-row input { margin-top: 0.2rem; flex: none; width: 1rem; height: 1rem; accent-color: var(--color-primary); }
.toggle-body { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.toggle-title { font-weight: 600; font-size: 0.9rem; }
.toggle-sub { font-size: 0.78rem; line-height: 1.4; color: var(--color-on-surface-variant); }

/* ── /Pay clinic bar ───────────────────────────────────────────────
   The clinic and its contract on their own line, ABOVE the money rather
   than as the header of a card that holds it. They used to head the one
   card carrying both periods, which is what made the payday pill beside
   the clinic name read as belonging to whichever figure the eye landed
   on first — the awaiting one or the accruing one, take your pick. */
.pay-clinic-bar {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.9rem;
}
.pay-clinic-bar-main { min-width: 0; }
.pay-clinic-bar h2 {
  margin: 0;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.15rem;
  letter-spacing: -0.01em;
}
.pay-clinic-bar .pay-summary { margin: 0.2rem 0 0; }
.pay-clinic-bar .btn { flex: none; }

/* Single-period history browser: arrows own their own row, because they
   navigate the tile below rather than belonging to it. */
.period-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.9rem;
}
.period-nav .period-title { text-align: center; min-width: 0; }
.period-nav .period-title strong { display: block; }
.period-nav-spacer { width: 5.5rem; }

/*  The range in the middle of that row is a dropdown, matching the app: the
    arrows move one period, and six back that way is six page loads.

    .period-title is shared with the plain-label fallback so the button and
    the label are the same object typographically — only the caret and the
    press states tell you this one opens. */
.period-picker { position: relative; min-width: 0; }
.period-picker-trigger {
  display: block;
  width: 100%;
  padding: 0.35rem 0.6rem;
  border: 1px solid transparent;
  border-radius: 0.65rem;
  background: none;
  font-family: inherit;
  color: inherit;
  cursor: pointer;
}
.period-picker-trigger strong {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
}
.period-picker-caret { font-size: 18px; color: var(--color-on-surface-variant); }
.period-picker-trigger:hover {
  border-color: var(--color-outline-variant);
  background: var(--color-surface-container-lowest);
}
.period-picker.open .period-picker-trigger {
  border-color: var(--color-outline-variant);
  background: var(--color-surface-container-lowest);
}
.period-picker.open .period-picker-caret { transform: rotate(180deg); }

.period-picker-menu {
  display: none;
  position: absolute;
  top: calc(100% + 0.35rem);
  /* Centred under a centred trigger, and allowed to be wider than it: the
     rows carry a range AND an amount, which a 12rem label can't hold. */
  left: 50%;
  transform: translateX(-50%);
  z-index: 60;
  width: max(100%, 19rem);
  max-height: 17rem;
  overflow-y: auto;
  padding: 0.3rem;
  text-align: left;
  background: var(--color-surface-container-lowest);
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.75rem;
  box-shadow: 0 16px 40px color-mix(in srgb, var(--color-on-surface) 20%, transparent);
}
.period-picker.open .period-picker-menu { display: block; }

.period-picker-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 0.6rem;
  border-radius: 0.5rem;
  color: var(--color-on-surface);
  text-decoration: none;
  font-size: 0.88rem;
}
.period-picker-row:hover { background: var(--color-surface-container); }
.period-picker-row.active {
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
  font-weight: 700;
}
.period-picker-row .money { font-variant-numeric: tabular-nums; }
.period-picker-row-range { display: inline-flex; align-items: center; gap: 0.4rem; min-width: 0; }
/* "now" — the period still accruing. Its amount is a running total, not a
   figure anyone was paid, and the tag is what says so in a list where every
   other row is settled. */
.period-picker-tag {
  padding: 0.05rem 0.35rem;
  border-radius: 9999px;
  background: var(--color-primary);
  color: var(--color-on-primary, #fff);
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.period-picker-row.active .period-picker-tag {
  background: var(--color-on-primary-container);
  color: var(--color-primary-container);
}

/* Reports list — same rhythm as the /Account invoice history. */
.report-list .row { align-items: center; }
/* A long title (simulations carry a scenario name AND a date range) used to
   win the space fight and squeeze the action cluster until its trash button
   wrapped under the PDF button — so two rows of the same list sat at
   different heights with differently-placed controls. The title yields
   instead: it wraps, the buttons stay a pair.
   Wrapping here was for the old inline delete-confirm, which grew the
   cluster to a question plus two buttons; that confirm is a page-level
   modal now, so a row's actions are always exactly download + trash. */
.report-list .row > .label { flex: 1 1 auto; min-width: 0; }
.report-list .report-actions { flex-wrap: nowrap; flex-shrink: 0; }
.report-download { display: inline-flex; align-items: center; gap: 0.3rem; white-space: nowrap; }
.report-download .material-symbols-outlined { font-size: 16px; }

/* ── /Pay period tiles ─────────────────────────────────────────────
   The closed period waiting on its payday and the period accruing right
   now used to be two headed sections inside ONE card, which is exactly
   what made the screen confusing: the same box held a settled figure
   with a date and a moving figure without one, and a "payday" pill at
   the top that could plausibly have belonged to either.

   They're separate tiles now, and the difference is carried on three
   independent channels so it survives a black-and-white printout and a
   colourblind reader:

     1. Fill      — settled is a saturated tile, open is an outlined card.
     2. State     — a "Final" chip vs a live pulsing dot and a period
                    progress track.
     3. Language  — "Lands Fri, Aug 7 · in 3 days" vs "so far",
                    "Closes Aug 8".

   Colour alone is never one of them: the app ships ten themes whose
   primary hue spans teal to terracotta to purple. */

.pay-checks {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  margin-bottom: 1.25rem;
}
@media (min-width: 860px) {
  .pay-checks { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.check-tile {
  /* Per-variant hairline / muted / chip tones, so every rule below can be
     written once and stay correct on both a white card and a saturated
     tile. */
  --check-line: var(--color-outline-variant);
  --check-muted: var(--color-on-surface-variant);
  --check-chip: var(--color-surface-container);

  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 1.35rem 1.35rem 1.15rem;
  /* Transparent rather than absent: the outlined variants carry a real
     1px edge, and without a matching one here the filled tile's rows sit
     a pixel higher than its neighbour's all the way down. */
  border: 1px solid transparent;
  border-radius: 1.25rem;
}

/* The settled period — money that has stopped moving and has a date on
   it. Same saturated treatment /Calendar/Day gives its headline figure,
   because it is the same kind of statement: this number is final. */
.check-settled {
  --check-line: color-mix(in srgb, var(--color-on-primary) 26%, transparent);
  --check-muted: color-mix(in srgb, var(--color-on-primary) 94%, transparent);
  --check-chip: color-mix(in srgb, var(--color-on-primary) 20%, transparent);

  background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dim));
  color: var(--color-on-primary);
  box-shadow: 0 18px 44px color-mix(in srgb, var(--color-primary) 26%, transparent);
}
.check-settled::after {
  /* Soft radial sheen — texture without introducing another colour. */
  content: "";
  position: absolute;
  top: -70%;
  left: -14%;
  width: 60%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--color-on-primary) 15%, transparent), transparent 70%);
  pointer-events: none;
}
.check-settled > * { position: relative; z-index: 1; }

/* The open period — outlined, never filled, because nothing in it is
   settled yet. */
.check-live {
  background: var(--color-surface-container-lowest);
  border: 1px solid var(--color-outline-variant);
  box-shadow: 0 16px 40px color-mix(in srgb, var(--color-on-surface) 6%, transparent);
}

/* Nothing in the mail / no open period. Kept as a tile rather than
   collapsed away so the pair keeps its shape and the reader learns what
   the missing half would have said. Solid border, never dashed —
   dashed edges mean "simulated" everywhere else on this page. */
.check-empty {
  background: var(--color-surface-container-low);
  border: 1px solid var(--color-outline-variant);
  color: var(--color-on-surface-variant);
}
.check-empty-body { margin: 0; font-size: 0.88rem; line-height: 1.5; }
.check-empty-body strong { color: var(--color-on-surface); }

.check-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}
.check-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: "Manrope", sans-serif;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.check-badge .material-symbols-outlined { font-size: 18px; line-height: 1; }
.check-state {
  flex: none;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  background: var(--check-chip);
  color: inherit;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Still counting. The animation is decoration on top of the word "Open"
   and the progress track — nothing here is the only carrier of state,
   so switching it off costs no meaning. */
.check-dot {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: var(--color-primary);
  animation: check-pulse 2.4s ease-out infinite;
}
@keyframes check-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-primary) 50%, transparent); }
  70%  { box-shadow: 0 0 0 0.5rem color-mix(in srgb, var(--color-primary) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-primary) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .check-dot { animation: none; }
}

.check-label {
  margin: 0.35rem 0 0;
  font-size: 0.78rem;
  color: var(--check-muted);
}
.check-amount {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
}
.check-amount-value {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: clamp(2rem, 4.4vw, 2.6rem);
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  line-height: 1.05;
}
/* "so far" rides on the number itself, not in a caption underneath —
   the qualifier has to be impossible to read past. */
.check-amount-tag {
  padding: 0.12rem 0.5rem;
  border-radius: 999px;
  background: var(--check-chip);
  font-size: 0.63rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
/* Stands in for the headline figure when there is no figure — see the
   CheckAmount helper in Pages/Pay/Index.cshtml. Deliberately NOT hero
   type: a sentence set at 2.6rem/800 would claim the weight of money
   that hasn't been earned. Muted and quiet, so the eye reads it as an
   answer and moves on to the progress track underneath. */
.check-amount-none {
  margin: 0;
  font-family: "Manrope", sans-serif;
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--check-muted);
}
.check-sim {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin: 0;
}
.check-note {
  margin: 0;
  font-size: 0.76rem;
  line-height: 1.45;
  color: var(--check-muted);
}

/* How far through the period we are — the one thing that says "this
   number is not finished" without any words at all. */
.check-track {
  height: 0.4rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--color-on-surface) 10%, transparent);
  overflow: hidden;
}
.check-track-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--color-primary);
}
.check-track-note {
  margin: -0.2rem 0 0;
  font-size: 0.73rem;
  color: var(--check-muted);
}

/* Facts — production, eligible, days worked. Deliberately smaller than
   the headline and never re-priced by a simulation, because they are
   what happened rather than what a contract pays for it. */
.check-stats {
  display: flex;
  flex-wrap: wrap;
  row-gap: 0.6rem;
  margin: 0.25rem 0 0;
}
.check-stats > div { min-width: 0; }
.check-stats > div + div {
  margin-left: 1.15rem;
  padding-left: 1.15rem;
  border-left: 1px solid var(--check-line);
}
.check-stats dt {
  font-size: 0.64rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--check-muted);
}
.check-stats dd {
  margin: 0.1rem 0 0;
  font-weight: 700;
  font-size: 0.94rem;
  font-variant-numeric: tabular-nums;
}

/* The odd extra figure (guaranteed floor) keeps the dashed-row rhythm the
   rest of the app uses — restated here because .account-card's version
   doesn't reach inside a tile. */
.check-rows { margin-top: 0.1rem; }
.check-tile .row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 0;
  font-size: 0.9rem;
  border-top: 1px dashed var(--check-line);
}
.check-tile .row .label { color: var(--check-muted); }
.check-tile .row .money { font-variant-numeric: tabular-nums; font-weight: 700; }

/* margin-top:auto pins the footer to the bottom, so two tiles of
   different heights still line their dates and export bars up.

   background/padding/margin are spelled out rather than left to default,
   because site.css carries a bare `footer { background; padding: 2.5rem 0 }`
   for the marketing page footer and it reaches any <footer> element
   nested in content. Unset here, it painted a pale slab with 2.5rem of
   dead air under it — and on the filled tile, near-white text landed on
   a near-white background. See website/RULES.md §10. */
.check-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin: auto 0 0;
  padding: 0.9rem 0 0;
  background: none;
  border-top: 1px solid var(--check-line);
}
.check-when {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.78rem;
  font-weight: 700;
}
.check-when .material-symbols-outlined { font-size: 17px; line-height: 1; }

/* The export bar has to invert on the saturated tile — its resting
   colours are tuned for a white card. */
.check-settled .export-bar { background: color-mix(in srgb, var(--color-on-primary) 16%, transparent); }
.check-settled .export-btn { color: inherit; }
.check-settled .export-btn:hover:not(:disabled) {
  background: color-mix(in srgb, var(--color-on-primary) 24%, transparent);
  color: inherit;
}

/* Simulated money on a tile: the hatch + dashed edge every provisional
   surface in this app wears, plus the inversion the struck-through
   "was" and the delta chip need on the saturated variant. */
.check-tile.sim-card { border: 1px dashed var(--color-outline); }
.check-live.sim-card,
.check-empty.sim-card {
  background:
    repeating-linear-gradient(
      135deg,
      color-mix(in srgb, var(--color-on-surface) 3.5%, var(--color-surface-container-lowest)) 0 7px,
      var(--color-surface-container-lowest) 7px 14px);
}
.check-settled.sim-card { border-color: color-mix(in srgb, var(--color-on-primary) 55%, transparent); }
.check-settled.sim-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(
      135deg,
      color-mix(in srgb, var(--color-on-primary) 9%, transparent) 0 7px,
      transparent 7px 14px);
  pointer-events: none;
}
.check-settled .sim-money-was { color: inherit; opacity: 0.8; }
.check-settled .sim-money-delta {
  background: color-mix(in srgb, var(--color-on-primary) 22%, transparent);
  color: inherit;
}

/* ── What actually landed ─────────────────────────────────────────
   Two related but deliberately separate records, and the CSS keeps them
   looking related without letting them look like the same thing:

     .settle — a pay period's cheque. A bank deposit. It explains a
               number; it never derives one.
     .amend  — one procedure's collection. This DOES re-price the
               contract, through every rule, on every screen.

   Both wear the same "amended" ink so a shortfall reads the same
   wherever it surfaces, and neither leans on hue to say so: a struck
   figure beside a live one, a word, and an icon carry it, because these
   pages get printed and the app ships ten themes whose primary hue spans
   teal to terracotta to purple.

   Everything here is a <details>. No script is involved in opening an
   editor, saving a figure or reporting a refusal — the /Pay tiles and
   /Calendar/Day are server-rendered, and a money control that stops
   working when a script fails is worse than no control. */

/* The shared "this is not what was billed" pair: the old figure struck
   through, the real one beside it. Inherits colour so it works on the
   filled tile and the white card alike. */
.amend-was {
  font-size: 0.82em;
  font-variant-numeric: tabular-nums;
  text-decoration: line-through;
  opacity: 0.55;
}
.amend-now {
  font-variant-numeric: tabular-nums;
  font-weight: 800;
}

/* ── the settlement strip ── */

.settle { margin-top: 0.35rem; }
.settle > summary { list-style: none; }
.settle > summary::-webkit-details-marker { display: none; }

/* The strip states what is KNOWN. Before a settlement exists it says
   "Payday" and a date, never "Paid" — a date passing is not a deposit,
   and asserting one from the calendar is the claim this whole feature
   exists to stop making. */
.settle-strip {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--check-line, var(--color-outline-variant));
  border-radius: 0.85rem;
  background: var(--check-chip, var(--color-surface-container));
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.settle-strip:hover { border-color: currentColor; }
.settle-strip:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}
.settle-icon { font-size: 20px; line-height: 1; flex: none; }
.settle-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.settle-label {
  font-family: "Manrope", sans-serif;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.settle-detail {
  font-size: 0.76rem;
  color: var(--check-muted, var(--color-on-surface-variant));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.settle-amount {
  flex: none;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  font-size: 0.95rem;
}
.settle-caret {
  flex: none;
  font-size: 20px;
  transition: transform 0.18s ease;
  color: var(--check-muted, var(--color-on-surface-variant));
}
.settle[open] .settle-caret { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  .settle-caret { transition: none; }
}

/* Outcome is carried by the ICON and the WORD first. The tint is a
   second channel on the outlined tile only — on the saturated one every
   status inherits the tile's ink, because a themed error red on the
   primary gradient is unreadable (website/RULES.md §10). */
.check-live .settle-strip-short,
.check-live .settle-strip-unpaid,
.account-card .settle-strip-short,
.account-card .settle-strip-unpaid {
  border-color: color-mix(in srgb, var(--color-error) 45%, transparent);
  background: color-mix(in srgb, var(--color-error) 8%, transparent);
}
.check-live .settle-strip-short .settle-icon,
.check-live .settle-strip-unpaid .settle-icon,
.account-card .settle-strip-short .settle-icon,
.account-card .settle-strip-unpaid .settle-icon { color: var(--color-error); }

.check-live .settle-strip-paid,
.account-card .settle-strip-paid {
  border-color: color-mix(in srgb, var(--color-primary) 45%, transparent);
  background: color-mix(in srgb, var(--color-primary) 8%, transparent);
}
.check-live .settle-strip-paid .settle-icon,
.account-card .settle-strip-paid .settle-icon { color: var(--color-primary); }

/* ── the settlement editor ── */

.settle-form {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-top: 0.5rem;
  padding: 0.85rem;
  border: 1px dashed var(--check-line, var(--color-outline-variant));
  border-radius: 0.85rem;
}
.settle-title,
.amend-title {
  margin: 0;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 0.9rem;
}
.settle-status,
.amend-reasons { display: flex; flex-wrap: wrap; gap: 0.4rem; }

/* Chips are real radios — the input is visually hidden rather than
   absent, so the group is still a group to a keyboard and a screen
   reader, and the whole thing survives with CSS disabled as a plain
   labelled radio list. */
.settle-chip,
.amend-chip { position: relative; display: inline-flex; cursor: pointer; }
.settle-chip input,
.amend-chip input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.settle-chip span,
.amend-chip span {
  display: inline-block;
  padding: 0.32rem 0.7rem;
  border: 1px solid var(--check-line, var(--color-outline-variant));
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1.2;
}
/* The selected chip is filled, not merely outlined. An inset ring alone
   was too quiet next to two unselected pills, and which outcome is
   currently recorded is the single most important thing this form
   says — reading it wrong means recording the wrong cheque. */
.settle-chip input:checked + span,
.amend-chip input:checked + span {
  border-color: transparent;
  background: var(--color-primary);
  color: var(--color-on-primary);
}
/* On the saturated tile the primary IS the background, so the fill
   inverts instead — same contrast, opposite direction. */
.check-settled .settle-chip input:checked + span {
  background: var(--color-on-primary);
  color: var(--color-primary);
}
.settle-chip input:focus-visible + span,
.amend-chip input:focus-visible + span {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.settle-hint,
.amend-hint {
  margin: 0;
  font-size: 0.76rem;
  line-height: 1.45;
  color: var(--check-muted, var(--color-on-surface-variant));
}

.settle-row,
.amend-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.45rem;
}
.settle-currency,
.amend-currency {
  font-weight: 800;
  opacity: 0.7;
}
.settle-input,
.amend-input,
.settle-note,
.amend-note,
.settle-date {
  padding: 0.42rem 0.6rem;
  border: 1px solid var(--check-line, var(--color-outline-variant));
  border-radius: 0.6rem;
  background: color-mix(in srgb, var(--color-surface-container-lowest) 92%, transparent);
  color: var(--color-on-surface);
  font: inherit;
  font-size: 0.88rem;
}
.settle-input,
.amend-input { width: 7.5rem; font-variant-numeric: tabular-nums; font-weight: 700; }
.settle-note,
.amend-note { width: 100%; }
.settle-date-label {
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--check-muted, var(--color-on-surface-variant));
  margin-left: auto;
}
.settle-input:focus-visible,
.amend-input:focus-visible,
.settle-note:focus-visible,
.amend-note:focus-visible,
.settle-date:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}

/* "Nothing paid" is a submit of its own, not a scripted "type a zero for
   me". Denied is the most common outcome by far and shouldn't cost a
   keystroke — and it must not need JavaScript to not cost one. */
.amend-zero {
  padding: 0.42rem 0.7rem;
  border: 1px dashed var(--check-line, var(--color-outline-variant));
  border-radius: 0.6rem;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 0.78rem;
  font-weight: 700;
  cursor: pointer;
}
.amend-zero:hover { border-style: solid; }

.settle-error,
.amend-error {
  margin: 0;
  padding: 0.4rem 0.6rem;
  border-radius: 0.5rem;
  background: color-mix(in srgb, var(--color-error) 12%, transparent);
  color: var(--color-error);
  font-size: 0.8rem;
  font-weight: 700;
}
/* On the saturated tile the themed error red is unreadable against the
   primary, so the refusal takes the tile's own ink and leans on a chip
   background instead — website/RULES.md §10. */
.check-settled .settle-error {
  background: var(--check-chip);
  color: inherit;
}

.settle-actions,
.amend-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.settle-save,
.amend-save,
.settle-remove,
.amend-remove {
  padding: 0.42rem 0.9rem;
  border-radius: 999px;
  border: 1px solid transparent;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 800;
  cursor: pointer;
}
.settle-save,
.amend-save {
  margin-left: auto;
  background: var(--color-primary);
  color: var(--color-on-primary);
}
.check-settled .settle-save {
  background: var(--color-on-primary);
  color: var(--color-primary);
}
.settle-remove,
.amend-remove {
  background: none;
  border-color: var(--check-line, var(--color-outline-variant));
  color: inherit;
}
.settle-remove:hover,
.amend-remove:hover { border-color: currentColor; }

/* The pre-adjustment figure under a tile's headline. Sits directly below
   the number it qualifies, never in the footer — a correction printed
   after the reader has already banked the big number arrives too late. */
.check-adj {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin: 0;
  font-size: 0.78rem;
  color: var(--check-muted, var(--color-on-surface-variant));
}
.check-adj-text { font-weight: 700; }

/* ── /Calendar/Day: visits → procedures → the amendment slip ── */

.amend-banner-wrap { margin-bottom: 0.85rem; }
.amend-banner {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  padding: 0.75rem 0.9rem;
  border: 1px solid color-mix(in srgb, var(--color-error) 40%, transparent);
  border-left-width: 4px;
  border-radius: 0.85rem;
  background: color-mix(in srgb, var(--color-error) 7%, transparent);
}
.amend-banner .material-symbols-outlined { font-size: 20px; color: var(--color-error); }
.amend-banner-title {
  margin: 0;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 0.9rem;
}
.amend-banner-sub {
  margin: 0.1rem 0 0;
  font-size: 0.8rem;
  color: var(--color-on-surface-variant);
}

.visit {
  border-top: 1px dashed var(--color-outline-variant);
}
.visit > summary { list-style: none; cursor: pointer; }
.visit > summary::-webkit-details-marker { display: none; }
.visit-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0;
}
.visit-row:hover .visit-who { color: var(--color-primary); }
.visit-main { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.visit-who { font-weight: 700; font-size: 0.9rem; }
.visit-meta { font-size: 0.75rem; color: var(--color-on-surface-variant); }
.visit-money {
  flex: none;
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}
.visit-caret {
  flex: none;
  font-size: 20px;
  color: var(--color-on-surface-variant);
  transition: transform 0.18s ease;
}
.visit[open] > summary .visit-caret { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .visit-caret, .pline-edit { transition: none; } }
.visit-empty { padding: 0 0 0.7rem; }

/* A visit holding a shortfall says so while collapsed — hidden behind a
   triangle is hidden. */
.amend-flag {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  margin-top: 0.15rem;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  color: var(--color-error);
}
.amend-flag .material-symbols-outlined { font-size: 15px; }

.plines {
  list-style: none;
  margin: 0 0 0.7rem;
  padding: 0 0 0 0.25rem;
  border-left: 2px solid var(--color-outline-variant);
}

.pline > summary { list-style: none; cursor: pointer; }
.pline > summary::-webkit-details-marker { display: none; }
.pline-row {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.45rem 0.5rem;
  border-radius: 0.6rem;
}
.pline-row:hover { background: var(--color-surface-container); }
.pline[open] > .pline-row { background: var(--color-surface-container); }
.pline-code {
  flex: none;
  min-width: 3.4rem;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  color: var(--color-primary);
  padding-top: 0.08rem;
}
.pline-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.pline-name { font-size: 0.86rem; line-height: 1.35; }
.pline-meta { font-size: 0.72rem; color: var(--color-on-surface-variant); }
.pline-adj {
  margin-top: 0.1rem;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  color: var(--color-error);
  overflow-wrap: anywhere;
}
.pline-money {
  flex: none;
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: 0.88rem;
}
.pline-edit {
  flex: none;
  font-size: 18px;
  color: var(--color-on-surface-variant);
  transition: color 0.15s ease;
}
.pline-row:hover .pline-edit,
.pline[open] .pline-edit { color: var(--color-primary); }
.pline-amended .pline-edit { color: var(--color-error); }

/* The amendment slip opens UNDER the line it corrects, never in a modal:
   a dialog would cover the one row the dentist is checking against their
   EOB. */
.amend {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  margin: 0 0 0.6rem 0.5rem;
  padding: 0.8rem;
  border: 1px dashed var(--color-outline-variant);
  border-radius: 0.8rem;
  background: var(--color-surface-container-lowest);
}

@media (max-width: 560px) {
  .visit-money, .pline-money { flex-direction: column; align-items: flex-end; gap: 0; }
  .settle-date-label { margin-left: 0; }
  .settle-input, .amend-input { width: 100%; }
}

/* ── Contract simulation ──────────────────────────────────────────
   Marked provisional WITHOUT colour: 135deg hatching, dashed edges and
   a stamp. Colour can't do this job — the companion app ships ten themes
   whose primary hue spans teal to terracotta to purple, and nothing
   chromatic survives the printout an accountant actually reads. */

/* Cards in .pay-wrap carry their own bottom margin, and the PDF reports
   card is the last one that did — so this needs its own top gap or it
   butts straight against the real reports above it. Set here rather than
   as a `.pay-wrap > .account-card + .account-card` rule because .pay-wrap
   is shared by nine pages that don't want their spacing changed. */
.sim-archive {
  margin-top: 1.25rem;
  border: 1px dashed var(--color-outline);
  background:
    repeating-linear-gradient(
      135deg,
      color-mix(in srgb, var(--color-on-surface) 3.5%, var(--color-surface-container-lowest)) 0 7px,
      var(--color-surface-container-lowest) 7px 14px);
}

.sim-archive h2 { display: flex; align-items: center; gap: 0.4rem; }
.sim-glyph { font-size: 20px; color: var(--color-on-surface-variant); }
.sim-lede { margin-top: -0.25rem; margin-bottom: 0.85rem; }

/* The what-if parameters now sit in the page header on every screen that
   has them, wearing .pay-sim-bar-chips — the inline-in-the-card variant is
   gone rather than left dormant. */
.sim-params-lede {
  margin: 0 0 0.6rem;
  font-size: 0.8rem;
  color: var(--color-on-surface-variant);
}

/* ── Pay-rules picker ─────────────────────────────────────────────
   A styled listbox standing in for a native <select>, matching the
   breadcrumb clinic switcher. A native select renders as OS chrome — a
   grey system popup that ignores every token here — and can't carry the
   per-option descriptions this choice deserves, since the two options
   produce genuinely different documents. */

.mode-picker { position: relative; display: block; }

.mode-picker-trigger {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.65rem;
  background: var(--color-surface-container-lowest);
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  text-align: left;
  color: var(--color-on-surface);
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
}

.mode-picker-trigger:hover { border-color: var(--color-outline); }
.mode-picker.open .mode-picker-trigger {
  border-color: var(--color-primary);
  background: var(--color-surface-container);
}

.mode-picker-icon { font-size: 18px; color: var(--color-primary); flex: none; }
.mode-picker-current { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mode-picker-caret {
  font-size: 18px;
  color: var(--color-on-surface-variant);
  flex: none;
  transition: transform 150ms ease;
}
.mode-picker.open .mode-picker-caret { transform: rotate(180deg); }

.mode-picker-menu {
  display: none;
  position: absolute;
  top: calc(100% + 0.35rem);
  left: 0;
  right: 0;
  z-index: 60;
  padding: 0.3rem;
  background: var(--color-surface-container-lowest);
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.75rem;
  box-shadow: 0 16px 40px color-mix(in srgb, var(--color-on-surface) 20%, transparent);
}
.mode-picker.open .mode-picker-menu { display: block; }

.mode-picker-option {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  width: 100%;
  padding: 0.55rem 0.6rem;
  border: none;
  border-radius: 0.5rem;
  background: transparent;
  font-family: inherit;
  text-align: left;
  color: var(--color-on-surface);
  cursor: pointer;
}
.mode-picker-option + .mode-picker-option { margin-top: 0.15rem; }
.mode-picker-option:hover { background: var(--color-surface-container); }
.mode-picker-option.active {
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
}
.mode-picker-option > .material-symbols-outlined:first-child {
  font-size: 18px;
  flex: none;
  margin-top: 0.05rem;
  color: var(--color-on-surface-variant);
}
.mode-picker-option.active > .material-symbols-outlined { color: var(--color-on-primary-container); }

.mode-picker-option-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.mode-picker-option-title { font-size: 0.85rem; font-weight: 700; }
.mode-picker-option-sub {
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--color-on-surface-variant);
  margin-top: 0.05rem;
}
.mode-picker-option.active .mode-picker-option-sub {
  color: color-mix(in srgb, var(--color-on-primary-container) 75%, transparent);
}

/* Only the selected row shows a tick — the others keep the space so the
   text columns stay aligned as the selection moves. */
.mode-picker-check { font-size: 18px; flex: none; margin-top: 0.05rem; visibility: hidden; }
.mode-picker-option.active .mode-picker-check { visibility: visible; }

.sim-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0 0 0.6rem;
}

.sim-chip {
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--color-outline-variant);
  border-radius: 999px;
  background: var(--color-surface-container-lowest);
  color: var(--color-on-surface-variant);
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 120ms, background 120ms, color 120ms;
}

.sim-chip:hover { border-color: var(--color-outline); }

/* An active tweak DOES take the theme colour: at that point it's a
   selection state, and selection is what the accent means everywhere
   else. The provisional signal stays with the card, not the chip. */
.sim-chip-on {
  border-color: var(--color-primary);
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
}

.sim-value {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0.35rem 0;
  font-size: 0.82rem;
  color: var(--color-on-surface-variant);
}

/* The local `.sim-value[hidden]` patch that used to live here is gone —
   site.css settles [hidden] globally now. */
.sim-value label { font-weight: 600; min-width: 7rem; }

.sim-value input {
  width: 6rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.5rem;
  background: var(--color-surface-container-lowest);
  color: var(--color-on-surface);
  font: inherit;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}

.sim-assume { margin: 0.6rem 0; }
.sim-assume summary {
  cursor: pointer;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--color-on-surface-variant);
}
.sim-assume > .muted-note { margin: 0.5rem 0; font-size: 0.78rem; }

.sim-anchor {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin-top: 0.5rem;
  font-size: 0.8rem;
  color: var(--color-on-surface-variant);
  cursor: pointer;
}

.sim-result { margin: 0.9rem 0 0.2rem; }

/* Both sets of terms, stacked. Never rendered apart — the contrast
   between the two lines is the disclaimer. */
.sim-terms {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.6rem;
  background: var(--color-surface-container-lowest);
  margin-bottom: 0.7rem;
}
.sim-terms > div { display: flex; gap: 0.6rem; align-items: baseline; }
.sim-terms span {
  flex: 0 0 5.5rem;
  font-size: 0.63rem;
  font-weight: 800;
  letter-spacing: 0.07em;
  color: var(--color-on-surface-variant);
}
.sim-terms strong { flex: 1; min-width: 0; font-size: 0.85rem; }

.sim-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}
.sim-table th {
  padding: 0.25rem 0.4rem;
  text-align: right;
  font-size: 0.63rem;
  font-weight: 800;
  letter-spacing: 0.07em;
  color: var(--color-on-surface-variant);
}
.sim-table th:first-child, .sim-table td:first-child {
  text-align: left;
  color: var(--color-on-surface-variant);
}
.sim-table td {
  padding: 0.3rem 0.4rem;
  text-align: right;
  border-bottom: 1px solid var(--color-outline-variant);
}
/* Actual stays present but quieter — it's the baseline, and the
   simulated figure is the one being interrogated. */
.sim-table td:nth-child(2) { color: var(--color-on-surface-variant); }
.sim-total td {
  padding-top: 0.45rem;
  font-weight: 800;
  border-bottom: none;
  font-size: 0.95rem;
}

.sim-assumptions {
  margin: 0.6rem 0 0;
  padding-top: 0.4rem;
  border-top: 1px dashed var(--color-outline-variant);
  font-size: 0.75rem;
  color: var(--color-on-surface-variant);
}

/* Inverted against the primary Generate button: neutral ink, hatched
   fill. You cannot mis-click your way into thinking this is the real
   export, because it doesn't look like the real export. */
.sim-export {
  margin-top: 0.85rem;
  border: 1px solid var(--color-outline);
  color: var(--color-on-surface-variant);
  background:
    repeating-linear-gradient(
      135deg,
      color-mix(in srgb, var(--color-on-surface) 7%, transparent) 0 6px,
      transparent 6px 12px);
}
.sim-export:disabled { opacity: 0.55; cursor: default; }

/* Rows carry the stamp even inside the Simulations card — they get
   screenshotted, and the card heading doesn't travel with them. */
.sim-row .label { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; }
.sim-stamp {
  padding: 0.05rem 0.35rem;
  border: 1px dashed var(--color-outline);
  border-radius: 0.3rem;
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  color: var(--color-on-surface-variant);
}
.sim-row .inv-date { flex-basis: 100%; }

/* ── /clinics editors ─────────────────────────────────────────── */
/* .clinic-summary and .clinic-actions used to dress the clinic cards on
   the old /clinics list. The rail replaced that list, and the stacked
   Manage/Remove pair those cards carried is exactly what this section
   stopped doing — so both are gone rather than left behind for someone to
   copy. */

/* The "make this the default" line at the top of a clinic's Details card.
   Only ever rendered on a clinic that isn't the default — on the one that
   is, the rail's star carries it and this row would be a status with no
   action standing in front of the form. */
.clinic-default {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin: 0 0 1.15rem;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.75rem;
  background: var(--color-surface-container-lowest);
}
.clinic-default > .material-symbols-outlined {
  flex: none;
  font-size: 19px;
  color: var(--color-primary);
  font-variation-settings: 'FILL' 1;
}
.clinic-default-text {
  flex: 1 1 14rem;
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--color-on-surface-variant);
}
.clinic-default-text strong { color: var(--color-on-surface); }
.clinic-default form { flex: none; margin: 0; }

/* The removal card at the foot of a clinic's pane. Tinted, not shouted:
   it's the last card on a page the user came to in order to EDIT the
   clinic, so it has to be findable without reading as a warning about the
   three cards above it. */
.card-danger {
  /* .account-card is borderless, so this states the whole border — the
     tint alone is too quiet at 4% to mark the card off. */
  border: 1px solid color-mix(in srgb, var(--color-error) 30%, var(--color-outline-variant));
  background: color-mix(in srgb, var(--color-error) 4%, var(--color-surface-container-lowest));
}
.card-danger h2 { color: var(--color-error); }

/* ── preference switch ────────────────────────────────────────────
   A single consequential choice, with the consequence stated under it.
   Built for Settings → Beta's privacy switch; named .pref-* rather than
   .privacy-* on purpose — /beta loads auth-ivory.css ON TOP of this
   stylesheet, and that page has its own .privacy / .state-on / .state-off
   in a different palette. Two definitions of one class name across two
   loaded sheets is a bug waiting for whoever edits either.

   The on/off explainer swaps in pure CSS off the hidden checkbox, so the
   words under the switch can never disagree with the switch. */
.pref-toggle {
  position: relative;
  margin-top: 0.25rem;
  padding: 0.95rem 1.05rem 1rem;
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.9rem;
  background: var(--color-surface-container-lowest);
}
/* Off-screen, not display:none — a hidden input keeps its focus stop, and
   the switch's focus ring is drawn from it. */
.pref-toggle-input {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0; margin: 0;
  pointer-events: none;
}
.pref-toggle-row {
  display: flex;
  align-items: flex-start;
  gap: 0.9rem;
  cursor: pointer;
}
.pref-toggle-ico {
  flex: none;
  font-size: 20px;
  margin-top: 1px;
  color: var(--color-on-surface-variant);
  transition: color 160ms ease;
}
.pref-toggle-label { flex: 1; min-width: 0; }
.pref-toggle-title {
  display: block;
  font-size: 0.95rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--color-on-surface);
}
.pref-toggle-sub {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--color-on-surface-variant);
}

/* Track + knob. One span, so the whole row stays a single hit target. */
.pref-switch {
  flex: none;
  position: relative;
  width: 42px; height: 24px;
  margin-top: 0.1rem;
  border-radius: 999px;
  background: var(--color-surface-container-high);
  border: 1.5px solid var(--color-outline-variant);
  transition: background 180ms ease, border-color 180ms ease;
}
.pref-switch::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 16px; height: 16px;
  border-radius: 999px;
  background: var(--color-on-surface-variant);
  box-shadow: 0 1px 3px color-mix(in srgb, var(--color-on-surface) 28%, transparent);
  transition: transform 180ms cubic-bezier(.2, .9, .3, 1.4), background 180ms ease;
}
/*  ON is the error colour, not the primary one. Switching transparency off
    is the choice with a cost — support stops being able to see what you're
    hitting — and a mint switch would read as "good, done". This is not a
    warning that the user did something wrong; it is a state that should
    stay visible. */
.pref-toggle-input:checked ~ .pref-toggle-row .pref-switch {
  background: var(--color-error);
  border-color: var(--color-error);
}
.pref-toggle-input:checked ~ .pref-toggle-row .pref-switch::after {
  transform: translateX(18px);
  background: var(--color-on-error, #fff);
}
.pref-toggle-input:checked ~ .pref-toggle-row .pref-toggle-ico { color: var(--color-error); }
.pref-toggle-input:focus-visible ~ .pref-toggle-row .pref-switch {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-error) 30%, transparent);
}

/* Exactly one of the two is ever in the flow. */
.pref-state {
  display: none;
  margin: 0.85rem 0 0;
  padding: 0.6rem 0.75rem;
  border-radius: 0.6rem;
  font-size: 0.83rem;
  line-height: 1.45;
}
.pref-state strong { font-weight: 700; }
.pref-state-off {
  background: color-mix(in srgb, var(--color-primary) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--color-primary) 26%, transparent);
  color: var(--color-on-surface);
}
.pref-state-on {
  background: var(--color-error-container);
  border: 1px solid color-mix(in srgb, var(--color-error) 32%, transparent);
  color: var(--color-on-error-container);
}
.pref-toggle-input:not(:checked) ~ .pref-state-off { display: block; }
.pref-toggle-input:checked ~ .pref-state-on { display: block; }

.pref-foot {
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
  margin: 0.7rem 0 0;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--color-on-surface-variant);
}
.pref-foot .material-symbols-outlined { font-size: 18px; flex: none; margin-top: 1px; }

@media (prefers-reduced-motion: reduce) {
  .pref-switch, .pref-switch::after, .pref-toggle-ico { transition: none; }
}
.card-danger form { margin: 0; }

/* ── clinic setup strip ───────────────────────────────────────────
   Splitting a clinic into three panes hid two of them behind a click,
   and the two it hid are the ones that make the product work — a clinic
   with no schedule and no compensation rules can't pay anyone. So an
   unfinished clinic says what it's missing, on the pane the section
   lands on, and stops saying it the moment both are set.

   Deliberately NOT a permanent checklist with ticks: a list that stays
   after it's complete is nagging, and a row that says "done" is a row
   that has to be read to learn it can be ignored. This one disappears.

   Above the cards rather than inside one — it's about the clinic, not
   about its address, and a prompt buried under a form is a prompt that
   arrives after the reader has already started typing. */
.clinic-setup {
  margin: 0 0 1.25rem;
  padding: 1rem 1.1rem 1.1rem;
  border: 1px solid color-mix(in srgb, var(--color-primary) 28%, var(--color-outline-variant));
  border-radius: 1rem;
  background: color-mix(in srgb, var(--color-primary) 5%, var(--color-surface-container-lowest));
}
.clinic-setup-title {
  margin: 0 0 0.6rem;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 0.95rem;
  letter-spacing: -0.01em;
  color: var(--color-on-surface);
}
.clinic-setup-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.clinic-setup-list a {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  padding: 0.65rem 0.75rem;
  border-radius: 0.7rem;
  background: var(--color-surface-container-lowest);
  color: var(--color-on-surface-variant);
  text-decoration: none;
  font-size: 0.85rem;
  line-height: 1.45;
}
.clinic-setup-list a:hover { background: var(--color-surface-container); }
.clinic-setup-list a > .material-symbols-outlined {
  flex: none;
  font-size: 20px;
  color: var(--color-primary);
  /* Optical: a 20px glyph on a 1.45 line sits high against the first
     line of a two-line label. */
  margin-top: 0.1rem;
}
.clinic-setup-label { flex: 1 1 auto; min-width: 0; }
.clinic-setup-label strong {
  display: block;
  color: var(--color-on-surface);
  font-weight: 700;
}
.clinic-setup-go { margin-top: 0.1rem; opacity: 0.6; }
.field-hint {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.75rem;
  color: var(--color-on-surface-variant);
}
.field-error {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.78rem;
  color: var(--color-error);
}
.check-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  cursor: pointer;
}
.check-row input[type="checkbox"] { accent-color: var(--color-primary); }
.comp-card .comp-advanced { margin-top: 0.25rem; }
.deduction-row {
  display: grid;
  grid-template-columns: 1.2fr 1.3fr 0.8fr auto auto;
  gap: 0.4rem;
  align-items: center;
  margin-bottom: 0.4rem;
}
.deduction-row input,
.deduction-row select { min-width: 0; }
.deduction-row .ded-before {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.75rem;
  color: var(--color-on-surface-variant);
  white-space: nowrap;
}
/* The old 1.6rem pill override is gone: it was the reason the same button
   looked like two different controls on /clinics and /procedures. The
   shared .ded-remove box now applies here too. */
#ded-add { margin: 0.25rem 0 0.5rem; }
@media (max-width: 560px) {
  .deduction-row { grid-template-columns: 1fr 1fr; }
}

/* ── /calendar month grid ─────────────────────────────────────── */
.cal-nav { display: flex; align-items: center; gap: 0.6rem; }
.cal-nav .btn { padding: 0.35rem 0.5rem; }
.cal-title { font-variant-numeric: tabular-nums; }
.cal-wrap { max-width: 1000px; }
/* Month figures, on the nav row. Same label-over-value shape as the Pay
   tiles' .check-stats — one idiom for "a number that means something",
   wherever it appears — instead of the muted sentence that used to sit
   under the arrows and read as a caption for them. */
.cal-stats {
  display: flex;
  flex-wrap: wrap;
  row-gap: 0.5rem;
  margin: 0;
}
.cal-stats > div { min-width: 0; }
/* Earnings are the figure people came for; production is context. */
.cal-stat-earned { color: var(--color-primary); }
/* Positioning host for the day hover card — see .bars-wrap. */
.cal-gridwrap { position: relative; }
.cal-stats > div + div {
  margin-left: 1.15rem;
  padding-left: 1.15rem;
  border-left: 1px solid var(--color-outline-variant);
}
.cal-stats dt {
  font-size: 0.64rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-on-surface-variant);
}
.cal-stats dd {
  margin: 0.1rem 0 0;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 0.3rem;
}
.cal-dow {
  text-align: center;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-on-surface-variant);
  padding-bottom: 0.2rem;
}
.cal-cell {
  position: relative;
  min-height: 5.2rem;
  background: var(--color-surface-container-lowest);
  border-radius: 0.6rem;
  padding: 0.35rem 0.4rem;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--color-on-surface) 4%, transparent);
}
.cal-cell.blank { background: transparent; box-shadow: none; }
.cal-cell.worked { background: var(--color-surface-container-low); }

/* Today. A month with nothing logged used to give no clue at all which
   square you were standing on — every cell was identical white. The ring
   locates the cell and the filled number locates the date inside it;
   both, because on a payday the cell already has a coloured pill and one
   more tint would just be a second wash of the same green. */
.cal-cell.today {
  box-shadow: inset 0 0 0 2px var(--color-primary),
              0 4px 14px color-mix(in srgb, var(--color-on-surface) 4%, transparent);
}
.cal-cell.today .cal-daynum {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.35rem;
  height: 1.35rem;
  padding: 0 0.3rem;
  border-radius: 999px;
  background: var(--color-primary);
  color: var(--color-on-primary);
  font-weight: 800;
}
.cal-today-note {
  position: absolute;
  left: 0.4rem;
  right: 0.4rem;
  bottom: 0.4rem;
  font-size: 0.62rem;
  line-height: 1.2;
  color: var(--color-on-surface-variant);
}

.cal-daynum {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--color-on-surface-variant);
}

/* Payday. A 16px outline glyph in the corner was easy to miss on the one
   day of the fortnight it matters most — it is now a filled pill that
   says the word, and the cell carries a tint so it reads from across the
   month rather than only when you look straight at it. */
.cal-cell.payday { background: color-mix(in srgb, var(--color-primary) 7%, var(--color-surface-container-lowest)); }
.cal-cell.payday.worked { background: color-mix(in srgb, var(--color-primary) 9%, var(--color-surface-container-low)); }
.cal-payday {
  position: absolute;
  top: 0.28rem;
  right: 0.3rem;
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  padding: 0.08rem 0.4rem 0.08rem 0.25rem;
  border-radius: 999px;
  background: var(--color-primary);
  color: var(--color-on-primary);
  font-size: 0.56rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.cal-payday .material-symbols-outlined { font-size: 13px; }
@media (max-width: 900px) {
  /* A 34px cell has no corner to put a badge in — absolutely positioned
     top-right, the pill landed straight on top of the day number. So on
     narrow screens the marker rejoins the flow and sits beside the date,
     where it cannot collide with anything, and gives up the filled pill
     for the bare glyph the design started with. */
  .cal-payday-text { display: none; }
  .cal-payday {
    position: static;
    display: inline-flex;
    vertical-align: middle;
    margin-left: 0.15rem;
    padding: 0;
    background: none;
    color: var(--color-primary);
  }
  .cal-payday .material-symbols-outlined { font-size: 12px; }
  /* Smaller ring so the date + coin pair still fits the cell. */
  .cal-cell.today .cal-daynum { min-width: 1.15rem; height: 1.15rem; padding: 0 0.2rem; }
  /* "Nothing logged yet" wrapped to three lines in a 22px column. The
     ring and the filled date already say which day this is. */
  .cal-today-note { display: none; }
}
.cal-chip {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin-top: 0.25rem;
  padding: 0.2rem 0.4rem;
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
  border-radius: 0.45rem;
  font-size: 0.7rem;
  line-height: 1.2;
}
.cal-chip.finalized { background: var(--color-surface-container-high); color: var(--color-on-surface); }
.cal-chip-clinic {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  min-width: 0;
}
.cal-chip-amount { font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
.cal-chip-check { font-size: 12px; color: var(--color-primary); }
.cal-footnote { margin-top: 0.85rem; }

/* ── days that collected less than they billed ──────────────────────
   The month grid is where a bad fortnight gets noticed, so a square
   that went short has to say so without being opened.

   Three channels, because one is never enough here: a stripe down the
   cell's left edge (reads from across the month), a glyph in the cell
   (reads on the square), and the amount struck through inside the chip
   (reads the actual number). Hue is a fourth, not the first — these
   pages get printed, and the app ships ten themes whose primary spans
   teal to terracotta to purple. */
.cal-cell.amended::before {
  content: "";
  position: absolute;
  top: 0.35rem;
  bottom: 0.35rem;
  left: 0;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--color-error);
}
/* Rides beside the day number rather than in a corner of its own. The
   corner was tried first, bottom-left: on a two-clinic day the second
   chip landed on top of it, and no amount of margin fixed that without
   the margin itself being wrong on every other day. Beside the date it
   shares the one row in the cell that is guaranteed to be free, and it
   pairs with the payday marker, which collapses to the same place on
   narrow screens. */
.cal-amend {
  display: inline-flex;
  vertical-align: middle;
  margin-left: 0.15rem;
  color: var(--color-error);
  pointer-events: none;
}
.cal-amend .material-symbols-outlined { font-size: 14px; line-height: 1; }

.cal-chip.amended {
  background: color-mix(in srgb, var(--color-error) 12%, var(--color-surface-container-lowest));
  color: var(--color-on-surface);
}
.cal-chip.amended .cal-chip-amount { color: var(--color-error); }
/* The struck "was" figure shrinks harder than the live one — it is
   context, and the chip has room for exactly one prominent number. */
.cal-chip-was { font-size: 0.62rem; }

.cal-stat-amended {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  color: var(--color-error);
}
.cal-stat-amended .material-symbols-outlined { font-size: 16px; line-height: 1; }
.cal-stat-earned .amend-was { margin-left: 0.4rem; font-size: 0.78rem; font-weight: 600; }
.cal-footnote-amend { color: var(--color-error); }

/* One line in the hover card, not folded into the note: the note says how
   the day is doing, this says the day is not what it looks like.

   The card is a near-black slab, and the themed error red measures about
   2:1 against it — unreadable. So this is the one place the shortfall
   does NOT take the error ink: it keeps the card's own light text and
   gets a translucent red chip behind it instead. Same trade the settled
   pay tile makes, and for the same reason (website/RULES.md §10). */
.bar-tip-amend {
  display: flex;
  align-items: flex-start;
  gap: 0.3rem;
  margin-top: 0.35rem;
  padding: 0.2rem 0.4rem;
  border-radius: 0.4rem;
  background: color-mix(in srgb, var(--color-error) 45%, transparent);
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1.35;
  color: inherit;
}
.bar-tip-amend .material-symbols-outlined { font-size: 15px; line-height: 1.25; flex: none; }

@media (max-width: 720px) {
  .cal-cell { min-height: 3.6rem; padding: 0.25rem; }
  .cal-chip-clinic { display: none; }   /* amounts only on phones */
  /* A 34px-wide chip fits one figure. The stripe and the glyph still
     flag the square; the struck "was" is what the day report is for. */
  .cal-chip-was { display: none; }
  .cal-amend .material-symbols-outlined { font-size: 12px; }
}

/* ── /procedures pricing + groups ─────────────────────────────── */
.clinic-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-bottom: 1rem;
}
.proc-results {
  position: relative;
  background: var(--color-surface-container-lowest);
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.6rem;
  margin-top: 0.3rem;
  overflow: hidden;
  box-shadow: 0 12px 30px color-mix(in srgb, var(--color-on-surface) 10%, transparent);
}
.proc-result {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.5rem 0.7rem;
  border: none;
  background: transparent;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.85rem;
  border-bottom: 1px dashed var(--color-outline-variant);
}
.proc-result:last-child { border-bottom: none; }
.proc-result:hover { background: var(--color-surface-container-low); }
.proc-result strong { color: var(--color-primary); margin-right: 0.35rem; }

/* A price level at rest: name, figure, then its actions. Editing happens
   in a dialog, so the row is read-only text rather than a line of inputs —
   six form controls per row turned a list you read once a year into
   something that looked like unsaved work every time it loaded.

   ONE grid for the whole list, each row contributing three cells through
   display:contents. That is what makes the figures line up: rows laid out
   independently cannot share a column, whatever widths they are given.
   Two earlier attempts prove it — the figure straight after the name put
   it somewhere different on every row, and a fixed width shoved it flush
   against the buttons, away from the name it belongs to.

   Columns are max-content / max-content / 1fr: the name column is as wide
   as the longest name, the figure column as wide as the longest figure,
   and all the slack falls between the figures and the actions. The two
   things being compared end up side by side on the left, and the controls
   stay out of their way. */
.label-rows {
  display: grid;
  grid-template-columns: max-content max-content 1fr;
  align-items: center;
  column-gap: 1.5rem;
}
.label-row { display: contents; }
.label-row > * {
  padding: 0.6rem 0;
  border-bottom: 1px dashed var(--color-outline-variant);
}
.label-row:last-of-type > * { border-bottom: none; }

/* Capped so one very long name can't starve the actions column. Below the
   cap the column still sizes itself to the content. */
.label-name {
  font-weight: 700;
  max-width: 22rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Right-aligned in its column and tabular, so the decimal points line up
   as well as the column edges do. */
.label-price {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.label-actions {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  justify-self: end;
}
/* The arrows and delete post to their own handlers; the form is only
   there to carry them, so it must not introduce a line of its own. */
.label-actions form { display: contents; }

@media (max-width: 560px) {
  /* Name and figure keep their line; the buttons drop below rather than
     squeezing all three across a phone. */
  .label-rows { grid-template-columns: max-content 1fr; column-gap: 1rem; }
  .label-actions { grid-column: 1 / -1; justify-self: start; padding-top: 0; }
  /* On two lines the separator belongs under the whole row, so only the
     last cell draws it. */
  .label-row > *:not(.label-actions) { border-bottom: none; padding-bottom: 0.15rem; }
}

/* The code list, on the same one-grid principle as the price levels: code,
   name, section, actions, with the columns shared down the whole list so
   the codes form a real column instead of a ragged left edge.

   The name column takes the slack — it's the only one whose length varies
   without limit — and the section sits right of it rather than floating
   next to the buttons. */
.code-rows {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr) max-content max-content;
  align-items: center;
  column-gap: 1.1rem;
}
.code-row { display: contents; }
.code-row > * {
  padding: 0.55rem 0;
  border-bottom: 1px dashed var(--color-outline-variant);
}
.code-row:last-of-type > * { border-bottom: none; }

.code-name {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}
/* The name itself truncates; the badges beside it must not. */
.code-name > .scope-badge { flex: none; }
.code-section {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-on-surface-variant);
  white-space: nowrap;
}

/* ── the list tables ───────────────────────────────────────────────
   Codes, price levels and priced procedures are all a real <table> now.

   They were a grid with a border on each cell, which looked fine until
   you saw it: column-gap leaves a hole in every separator, so each row
   read as three or four disconnected fragments. Collapsed table borders
   have no gaps to break at.

   The other reason is Pricing specifically. One column per price level
   is the only layout that lets you compare Cash against PPO down the
   whole list rather than one procedure at a time — and a column per
   level is a table, however it's built. */
.proc-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.proc-table {
  width: 100%;
  /* `separate` with zero spacing, not `collapse`. Visually identical —
     each cell draws its own bottom rule and the cells touch, so the
     separators stay continuous — but a collapsed table discards
     border-radius on its cells, and the open row needs rounded corners
     to read as one block with its detail. */
  border-collapse: separate;
  border-spacing: 0;
  font-size: 0.9rem;

  /* The open row and its detail share one wash, keyed to the accent so
     it can never be mistaken for the neutral hover tint — which is
     exactly what it was before: both were surface-container-low, so
     pointing at a row painted it the same colour as an open one. */
  --proc-open: color-mix(in srgb, var(--color-primary) 9%, var(--color-surface-container-lowest));
  --proc-hover: color-mix(in srgb, var(--color-on-surface) 4%, transparent);
  --proc-rule: color-mix(in srgb, var(--color-outline-variant) 50%, transparent);
  --proc-open-radius: 0.85rem;
}
.proc-table th {
  padding: 0 0 0.55rem;
  text-align: left;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-on-surface-variant);
  border-bottom: 1px solid var(--color-outline-variant);
  white-space: nowrap;
}
/* Solid hairlines rather than dashes. Dashes are the house rule for a
   label→value list, where they say "these two belong on one line"; in a
   grid of records they only add texture, and five dashed lines under a
   row of micro-caps read as a form nobody filled in. */
.proc-table td {
  padding: 0.62rem 0;
  border-bottom: 1px solid var(--proc-rule);
  vertical-align: middle;
  transition: background-color 130ms ease;
}
/* No rule under the last record. On the codes list every row is trailed
   by its own detail row, so the last VISIBLE row is the second-to-last
   child — matching on :last-child alone left one hairline hanging under
   the list. */
.proc-table tbody tr:last-child td,
.proc-table tbody tr:has(+ .detail-row:last-child) > td { border-bottom: none; }
/* Gutters as padding rather than border-spacing, so the separators stay
   continuous across them. */
.proc-table th + th,
.proc-table td + td { padding-left: 1rem; }
/* End margins for the two columns that hold a round button: a circle set
   flush against the edge of the card looks clipped even when it isn't,
   and the chevron had the open row's spine running down its side. Only
   those columns, so a list that starts with text — the pricing table —
   keeps its first column flush with the heading above it. */
.proc-table th.col-expand,
.proc-table td.col-expand { padding-left: 0.5rem; }
.proc-table th.col-actions,
.proc-table td.col-actions { padding-right: 0.5rem; }

.proc-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* A figure the procedure hasn't been given at that level — it falls back
   to the level's standard price. Dimmed so a column of real prices and a
   column of defaults don't read as the same decision. */
.proc-table .price-default { color: var(--color-on-surface-variant); opacity: 0.7; }

.proc-table .col-actions {
  width: 1%;
  text-align: right;
  white-space: nowrap;
}
.proc-table .col-actions .label-actions { justify-content: flex-end; }
/* Matched to .btn-sm's height, so Edit and the bin next to it are one
   control group rather than a pill beside a taller square. */
.proc-table .col-actions .icon-btn {
  width: 2.15rem;
  height: 2.15rem;
  border-radius: 9999px;
}
.proc-table .col-actions .icon-btn .material-symbols-outlined { font-size: 18px; }
.proc-table .cell-code { white-space: nowrap; }
.proc-table .cell-name { min-width: 9rem; }
/* The whole row opens the detail, so it has to look like it does. The
   class is added by procedures.js rather than the markup, so only rows
   that actually have something to expand get the affordance. */
.proc-table tr.is-expandable { cursor: pointer; }
.proc-table tr.is-expandable:hover > td { background: var(--proc-hover); }
/* Except the actions cell, which does something else. */
.proc-table tr.is-expandable .col-actions { cursor: default; }

/* ── the open row and its detail ───────────────────────────────────
   One block, not two: a shared accent wash, a spine down the left, the
   rule between them dropped, and the corners rounded top and bottom so
   the pair closes as a single shape. A reader should never have to work
   out which row a detail belongs to. */
.proc-table tr.is-open > td,
.proc-table tr.is-open:hover > td { background: var(--proc-open); }
/* Removed, not made transparent. An inset shadow paints inside the
   border, so a 1px transparent bottom border cut a visible notch out of
   the spine exactly where the row met its detail. */
.proc-table tr.is-open > td { border-bottom: 0; }
.proc-table tr.is-open > td:first-child {
  border-top-left-radius: var(--proc-open-radius);
  box-shadow: inset 3px 0 0 var(--color-primary);
}
.proc-table tr.is-open > td:last-child { border-top-right-radius: var(--proc-open-radius); }

/* Expander column: as narrow as its button. */
.proc-table .col-expand { width: 1%; padding-right: 0; }
.proc-table .expander {
  width: 2rem;
  height: 2rem;
  border: none;
  border-radius: 9999px;
  background: transparent;
  transition: background-color 130ms ease, color 130ms ease;
}
.proc-table .expander:hover { background: var(--color-surface-container-high); }
.proc-table tr.is-open .expander {
  background: color-mix(in srgb, var(--color-primary) 16%, transparent);
  color: var(--color-primary);
}
.proc-table .expander .material-symbols-outlined { font-size: 20px; }

/* The row underneath a code: where it's filed, and what it costs here.
   Two questions the list can't answer without sending the reader to
   another pane, which is the whole reason it exists. */
.proc-table .detail-row > td {
  padding: 0 0.5rem 0.7rem;
  background: var(--proc-open);
  /* The gap under the block is a transparent border rather than padding,
     because padding would be painted with the wash. Open two codes next
     to each other and their blocks ran together into one field of
     colour with no telling where the first ended. */
  border-bottom: 0.5rem solid transparent;
  background-clip: padding-box;
  border-radius: 0 0 var(--proc-open-radius) var(--proc-open-radius);
  box-shadow: inset 3px 0 0 var(--color-primary);
}
/* Two fields, side by side while there's room. Deliberately NOT the same
   height: one holds a word and the other holds a price list that grows
   with the number of price levels, and stretching them to match put a
   hole between the caption and the value in the short one. Each tile is
   as tall as what's in it. */
.code-detail {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  align-items: start;
  gap: 0.5rem;
  /* Aligned with the Code column, not the table edge: the detail is
     about the code, so it starts where the code does. (2rem is the
     expander column plus the gutter after it — measured, not guessed.) */
  padding-left: 2rem;
}
/* A tile is a caption bar and a body: the caption and its action share
   the top line, the value fills the width underneath. The action sits
   on the caption rather than beside the value, so both tiles put their
   button on the same line whatever their bodies are doing. */
.code-detail-block {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-content: start;
  column-gap: 0.75rem;
  row-gap: 0.3rem;
  padding: 0.5rem 0.55rem 0.7rem 0.85rem;
  background: var(--color-surface-container-lowest);
  border-radius: 0.75rem;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-outline-variant) 45%, transparent);
}
/* A caption, not a heading of equal rank. Bold micro-caps at 0.66rem
   against a 0.92rem regular value came out at nearly the same weight on
   screen, so the pair read as two labels; the value has to be the thing
   you see first and the label the thing you read to place it. */
.code-detail-label {
  grid-area: 1 / 1;
  align-self: center;
  font-size: 0.63rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: color-mix(in srgb, var(--color-on-surface-variant) 78%, transparent);
}
/* Full width under the caption, so a price list has the whole tile to
   lay itself out in rather than a column beside the button. */
.code-detail-value {
  grid-area: 2 / 1 / auto / -1;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--color-on-surface);
  min-width: 0;
}
/* An empty value, not a quieter label: same size as a real one so the
   line doesn't collapse, but plainly unset. */
.code-detail-value .muted-note {
  font-size: 0.95rem;
  font-weight: 400;
  font-style: italic;
}
.code-detail-value > .num { font-variant-numeric: tabular-nums; }
/* On the caption line, and a floor width so the two actions are the same
   size even though "Change" and "Set price" are not. */
.code-detail .btn {
  grid-area: 1 / 2;
  min-width: 6.25rem;
  justify-content: center;
}
.code-detail .btn-secondary:hover { background: var(--color-surface-container-high); }

/* The price list is a two-column table, not a run of inline pairs: names
   left, figures right in their own column so they line up on the decimal
   point down however many levels the dentist keeps. `display: contents`
   on each pair is what lets both columns be shared by every row.

   Laid out inline they wrapped wherever they happened to, and the names
   were set in the same micro-caps as the tile's caption, so a caption, a
   price level and a figure all read as one texture. */
.code-detail-prices {
  display: grid;
  grid-template-columns: minmax(0, 1fr) max-content;
  column-gap: 1.25rem;
  row-gap: 0.15rem;
}
.code-detail-price { display: contents; }
.code-detail-price-label {
  align-self: baseline;
  font-size: 0.82rem;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  color: var(--color-on-surface-variant);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.code-detail-price .num {
  align-self: baseline;
  text-align: right;
  font-size: 0.95rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* Same meaning as in the pricing table: a figure inherited from the
   level's standard price rather than one chosen for this procedure.
   Dimmed per cell — the pair itself has no box to fade. */
.code-detail-price.price-default > * { opacity: 0.62; }

.proc-table .cell-quiet {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-on-surface-variant);
  white-space: nowrap;
}
/* A category is a name, not a status. It was set in the same micro-caps
   the column headings use, so every row repeated something that looked
   like a header; a soft tag says "filed under" and stops competing. */
.proc-table .cell-tag { white-space: nowrap; }
.cat-tag {
  display: inline-block;
  max-width: 12rem;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
  padding: 0.16rem 0.6rem;
  border-radius: 9999px;
  background: color-mix(in srgb, var(--color-primary) 9%, transparent);
  color: color-mix(in srgb, var(--color-primary) 72%, var(--color-on-surface));
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
}

@media (max-width: 720px) {
  /* The trailing label drops off first — the section is already a filter
     above the list, and the pay rule is in the row's own dialog. It's the
     column each list can lose without losing what it's for. */
  .code-rows { grid-template-columns: max-content minmax(0, 1fr) max-content; }
  .priced-rows {
    grid-template-columns: max-content minmax(0, 1fr) max-content max-content;
  }
  .code-section { display: none; }
}
@media (max-width: 560px) {
  .code-rows { grid-template-columns: max-content minmax(0, 1fr); }
  .priced-rows { grid-template-columns: max-content minmax(0, 1fr) max-content; }
  .label-actions { grid-column: 1 / -1; justify-self: start; }
  .code-row > *:not(.label-actions) { border-bottom: none; padding-bottom: 0.15rem; }
}

.proc-table-card { margin-top: 1.25rem; }
.proc-row { border-bottom: 1px dashed var(--color-outline-variant); }
.proc-row:last-of-type { border-bottom: none; }
.proc-row summary {
  display: grid;
  grid-template-columns: 4.5rem 1fr auto auto;
  gap: 0.6rem;
  align-items: center;
  padding: 0.55rem 0.2rem;
  cursor: pointer;
  font-size: 0.9rem;
  list-style: none;
}
.proc-row summary::-webkit-details-marker { display: none; }
.proc-row[open] summary { background: var(--color-surface-container-low); border-radius: 0.5rem; }
.proc-code { font-weight: 800; color: var(--color-primary); font-variant-numeric: tabular-nums; }
.proc-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.proc-salary {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-on-surface-variant);
  white-space: nowrap;
}
.proc-edit { padding: 0.6rem 0.2rem 0.9rem; }
.proc-options { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 0.6rem; }
.proc-option {
  display: grid;
  grid-template-columns: 1fr 7rem;
  gap: 0.5rem;
  align-items: center;
  font-size: 0.85rem;
}
.proc-edit-actions { display: flex; gap: 0.5rem; margin-top: 0.6rem; }

.group-row .group-actions { display: flex; align-items: center; gap: 0.4rem; }
.group-row.editing { background: var(--color-surface-container-low); border-radius: 0.5rem; padding-left: 0.4rem; padding-right: 0.4rem; }
.member-rows { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.5rem; }
.member-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.35rem 0.25rem 0.75rem;
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
  border-radius: 9999px;
  font-size: 0.8rem;
}
/* The ✕ inside a chip, not the standalone icon button — it has to sit
   INSIDE a 28px pill, so it borrows the centring but none of the box. */
.chip-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.35rem;
  height: 1.35rem;
  flex: none;
  padding: 0;
  border: none;
  border-radius: 9999px;
  background: transparent;
  color: inherit;
  cursor: pointer;
  line-height: 0;
  opacity: 0.7;
}
.chip-remove .material-symbols-outlined { font-size: 16px; }
.chip-remove:hover {
  opacity: 1;
  background: color-mix(in srgb, var(--color-on-primary-container) 15%, transparent);
}
@media (max-width: 560px) {
  .proc-row summary { grid-template-columns: 3.6rem 1fr auto; }
  .proc-row summary .proc-salary { display: none; }
}

/* ── /procedures section panes ────────────────────────────────────
   Procedures is five panes behind one rail (Pages/Shared/_ProceduresNav),
   reusing .settings-wrap / .settings-nav / .settings-link wholesale. That
   isn't a shortcut: the rail's own comment describes a QUIET index inside
   a page, which is exactly what a second vertical nav next to the app
   sidebar has to be, and a near-copy under a different name would drift
   from it the first time either is touched. Only what Procedures needs on
   TOP of that shell lives here. */

/* Square icon button — reorder arrows, remove, anything that is one glyph
   and no label.

   It used to be a 1.6rem pill wrapping a bare &times;. Two problems: a
   text glyph sits on the baseline, so it rode high in its own circle and
   never looked centred, and 25px is both dwarfed by the 48px controls
   beside it and under any sane tap-target floor. Now it's a flex box that
   centres a real icon, sized and cornered to match the inputs it sits
   next to.

   .ded-remove is the older name, kept because /clinics uses it; both get
   the same box so the same control can't look like two different ones on
   two screens. */
.icon-btn,
.ded-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  flex: none;
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.7rem;
  background: var(--color-surface-container-lowest);
  color: var(--color-on-surface-variant);
  cursor: pointer;
  /* 1, not 0: /clinics still puts a bare ✕ character in one of these, and
     a collapsed line box shifts a text glyph off-centre in some engines.
     Flex does the centring either way. */
  line-height: 1;
  font-family: inherit;
  font-size: 0.9rem;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.icon-btn .material-symbols-outlined,
.ded-remove .material-symbols-outlined { font-size: 19px; }

.icon-btn:hover,
.ded-remove:hover {
  background: var(--color-surface-container-high);
  color: var(--color-on-surface);
}
/* Destructive only on hover — a row of permanently red buttons reads as a
   list of errors. The label still says what it does. */
.icon-btn-danger:hover,
.ded-remove:hover {
  background: var(--color-error-container);
  color: var(--color-on-error-container);
  border-color: transparent;
}
.icon-btn[disabled],
.ded-remove[disabled] {
  opacity: 0.35;
  cursor: default;
}
.icon-btn[disabled]:hover,
.ded-remove[disabled]:hover {
  background: var(--color-surface-container-lowest);
  color: var(--color-on-surface-variant);
  border-color: var(--color-outline-variant);
}

/* What the clinic in the breadcrumb actually governs on THIS pane.
   Needed because it isn't the same answer twice: Pricing and Price labels
   are entirely one clinic's, Groups and Categories are a mix, and on the
   codes pane the clinic barely matters at all — renaming and hiding are
   account-wide. A single header control over five panes that mean five
   different things is the part that misleads, so each pane says its own
   piece rather than the chrome implying one rule for all of them.

   A quiet filled line, not an .alert-info: this is standing context, and
   a notice styled like a message is a message the reader waits to be able
   to dismiss. */
.pane-scope {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  /* It explains the pane, so it belongs to the heading above it, not to
     the search box below. */
  margin: 0 0 1.15rem;
  padding: 0.6rem 0.8rem;
  /* Accent-tinted rather than grey. In grey it was the same pale fill
     as the search field and the select beside it, at a different radius
     — three quiet boxes that looked related and weren't. */
  background: color-mix(in srgb, var(--color-primary) 6%, var(--color-surface-container-lowest));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 16%, transparent);
  border-radius: 0.85rem;
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--color-on-surface-variant);
}
.pane-scope .material-symbols-outlined {
  font-size: 18px;
  flex: none;
  margin-top: 0.05rem;
  color: var(--color-primary);
  opacity: 0.85;
}
.pane-scope strong { color: var(--color-on-surface); font-weight: 700; }

/* ── /procedures overview ──────────────────────────────────────────
   The section lands here rather than on the code list. Five panes that
   refer to each other is a model worth drawing once, instead of leaving
   the reader to infer it from a rail.

   The diagram is inline SVG for the same reason the icons are a local
   font: it has to work offline, and it has to follow all four themes —
   which it does by painting from the same custom properties everything
   else uses, rather than from baked-in hex. */
.proc-map {
  display: block;
  width: 100%;
  height: auto;
  max-width: 42rem;
  margin: 0.75rem auto 0;
  font-family: inherit;
}
.proc-map .node { fill: var(--color-surface-container-low); stroke: var(--color-outline-variant); }
/* Codes are the hub — everything else on the page points at them, so the
   one filled box is the one the reader should look at first. */
.proc-map .node-hub { fill: var(--color-primary-container); stroke: none; }
.proc-map .node-label { fill: var(--color-on-surface); font-size: 15px; font-weight: 700; }
.proc-map .node-label-hub { fill: var(--color-on-primary-container); }
.proc-map .node-count { fill: var(--color-on-surface-variant); font-size: 12px; }
.proc-map .node-count-hub { fill: var(--color-on-primary-container); opacity: 0.75; }
.proc-map .link { stroke: var(--color-outline-variant); stroke-width: 1.5; fill: none; }
.proc-map .arrow { fill: var(--color-outline-variant); }
.proc-map .link-label {
  fill: var(--color-on-surface-variant);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
}

/* The same five things as links, because the diagram explains and the
   cards are how you leave. */
.proc-guide {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 0.6rem;
  margin-top: 1.4rem;
}
.proc-guide-card {
  display: flex;
  gap: 0.65rem;
  padding: 0.8rem 0.9rem;
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.8rem;
  background: var(--color-surface-container-lowest);
  color: inherit;
  text-decoration: none;
}
.proc-guide-card:hover {
  background: var(--color-surface-container-low);
  border-color: transparent;
}
.proc-guide-card > .material-symbols-outlined {
  font-size: 20px;
  flex: none;
  margin-top: 0.1rem;
  color: var(--color-primary);
}
/* The card's body is spans, not divs — it lives inside an <a>, and a
   block-level child of an inline-content anchor is invalid. Made to stack
   here instead. */
.proc-guide-card > span:last-child { display: block; min-width: 0; }
.proc-guide-name { display: block; font-weight: 700; font-size: 0.9rem; }
.proc-guide-what {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--color-on-surface-variant);
}
.proc-guide-count {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-on-surface-variant);
  opacity: 0.8;
}

/* Card title with its primary action on the right. The add forms used to
   be a second card under the list, which put "add a section" a full
   screen below the sections on a catalog with a dozen of them — the one
   action on the pane, reachable only by scrolling past everything it
   wasn't. */
.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 0.4rem;
}
.card-head h2 { margin: 0; }
/* The blurb under a card heading is part of the heading, and .muted-note
   carries no margin of its own — so without this the description sat
   directly on whatever came next, usually a search field. */
.card-head + .muted-note { margin-bottom: 0.9rem; }

/* Sits in a title row, so it can't carry the full 52px .btn height. */
.btn-sm {
  padding: 0.45rem 0.95rem;
  font-size: 0.85rem;
  min-height: 0;
}

/* ── add dialogs ───────────────────────────────────────────────────
   Native <dialog> + showModal(): the focus trap, the Escape key, the
   inert background and the top-layer stacking are all the browser's,
   and none of them are worth reimplementing in a page that otherwise
   ships no framework.

   The form inside posts normally and the page reloads, so a failed save
   reopens the dialog server-side with what was typed still in it — see
   data-open-on-load. */
.proc-modal {
  width: min(34rem, calc(100vw - 2rem));
  padding: 0;
  border: none;
  border-radius: 1rem;
  background: var(--color-surface-container-lowest);
  color: var(--color-on-surface);
  box-shadow: 0 24px 60px color-mix(in srgb, var(--color-on-surface) 28%, transparent);
}
/* The group editor carries a search field, a growing list of chips and a
   fee plus salary rule. At 34rem the chips wrap every second one. */
.proc-modal-wide { width: min(44rem, calc(100vw - 2rem)); }

/* ── delete confirmations ──────────────────────────────────────────
   These replaced window.confirm(). Not for looks: confirm() can only ask
   one sentence, so every delete on these screens asked "are you sure?"
   without ever saying what would happen — and the one thing a dentist
   needs before deleting a code is whether the visits they've already
   logged go with it. (They don't. procedure_lines keeps its own copy of
   the code, label and price, and has no foreign key back.)

   So the shape is: what it is, what it takes with it, what it leaves
   alone, then the question. */
.proc-modal-danger { width: min(32rem, calc(100vw - 2rem)); }
.proc-modal-danger .proc-modal-head { gap: 0.85rem; align-items: flex-start; }

/* The mark carries the alarm so the buttons don't have to shout. */
.danger-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  flex: none;
  border-radius: 9999px;
  background: color-mix(in srgb, var(--color-error-container) 80%, transparent);
  color: var(--color-error);
}
.danger-mark .material-symbols-outlined { font-size: 22px; }

/* Consequences, one per line. A paragraph of them gets skimmed as a
   paragraph; a list gets read as a list. */
.danger-impacts {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.danger-impacts li {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  font-size: 0.86rem;
  line-height: 1.45;
  color: var(--color-on-surface-variant);
}
.danger-impacts .material-symbols-outlined {
  font-size: 18px;
  flex: none;
  margin-top: 0.1rem;
}
/* What survives reads differently from what goes — same list, so the
   reader doesn't have to hold two sections in their head. */
.danger-impacts .impact-loss .material-symbols-outlined { color: var(--color-error); }
.danger-impacts .impact-keep .material-symbols-outlined { color: var(--color-primary); }

.danger-ask {
  margin: 1rem 0 0;
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--color-on-surface);
}

/* Destructive confirm. Only ever the second button in a footer, next to a
   Cancel that is the safe default — never a lone red button somewhere a
   stray click can find it. */
.btn-danger {
  background: var(--color-error);
  color: var(--color-on-error, #fff);
  border: none;
  box-shadow: none;
}
.btn-danger:hover {
  background: color-mix(in srgb, var(--color-error) 85%, #000);
  color: var(--color-on-error, #fff);
}

.proc-modal::backdrop {
  background: color-mix(in srgb, var(--color-on-surface) 45%, transparent);
}
.proc-modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.2rem 1.35rem 0.5rem;
}
.proc-modal-head h2 { margin: 0; font-size: 1.05rem; }
.proc-modal-head .muted-note { margin: 0.3rem 0 0; }
/* Scrolls its own body rather than the dialog, so the footer buttons
   stay put on a short phone screen.

   The vertical padding is not spacing — it's clearance for the focus
   ring. That ring is a 3px box-shadow, which paints OUTSIDE the input,
   and an overflow container clips anything past its edge: the field the
   dialog autofocuses is the first one, so its ring was being sliced off
   along the top. Same at the bottom for the last field. */
.proc-modal-body {
  padding: 0.5rem 1.35rem;
  max-height: 60vh;
  overflow-y: auto;
  /* Keeps the ring clear of the edge when a field is scrolled to as well,
     not only when it happens to be first. */
  scroll-padding: 0.5rem 0;
}
.proc-modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 1rem;
  padding: 0.9rem 1.35rem 1.15rem;
  border-top: 1px dashed var(--color-outline-variant);
}
/* The message slots inside a dialog already sit above the footer rule,
   so they don't need the standing bottom margin as well. */
.proc-modal-body .scope-msg { margin-bottom: 0.2rem; }

@media (max-width: 560px) {
  .proc-modal-foot .btn { flex: 1 1 100%; justify-content: center; }
}

/* Search + filters above a list. Wraps rather than scrolls: these are
   controls, and a control that has scrolled out of sight is a control
   nobody knows about. */
.proc-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 0.9rem;
}
.proc-toolbar .proc-search { flex: 1 1 12rem; min-width: 0; }
.proc-toolbar select { flex: 0 1 11rem; min-width: 0; }

/* Source filters — All / Mine / Renamed / Hidden. Deliberately lighter
   than .pay-tab: those switch the page, these narrow a list that stays
   put, and pills loud enough to read as navigation would say otherwise.
   The count rides inside the chip so the list can be empty without the
   screen looking broken. */
.filter-chips { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--color-outline-variant);
  border-radius: 9999px;
  background: transparent;
  color: var(--color-on-surface-variant);
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.filter-chip:hover { background: var(--color-surface-container-low); }
.filter-chip.active {
  background: var(--color-surface-container-high);
  border-color: transparent;
  color: var(--color-on-surface);
}
.filter-chip .chip-count {
  font-variant-numeric: tabular-nums;
  opacity: 0.65;
  font-weight: 700;
}

/* Which clinics a row applies to. Text, not a colour: ten themes ship and
   nothing may be carried by hue alone (RULES §2). */
.scope-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.1rem 0.45rem;
  border-radius: 9999px;
  background: var(--color-surface-container-high);
  color: var(--color-on-surface-variant);
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.scope-badge.scope-all {
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
}

.scope-hint {
  margin: 0.35rem 0 0;
  font-size: 0.78rem;
  line-height: 1.4;
  color: var(--color-on-surface-variant);
}

/* ── live messages under a form's clinic picker ────────────────────
   Two of them, one shape: the conflict line ("that name is taken") and
   the widening warning ("saving will also move this code"). Both are
   written by script as the dentist types, both sit directly above the
   button they're about it, and both were previously a bare paragraph
   that ended up touching it.

   The shared frame is an icon column, a bold lead and a lighter detail
   line — the lead is the fact, the detail is what follows from it, and
   splitting them means the sentence that matters survives being skimmed.
   Generous margin-bottom is the point of the exercise: a message flush
   against a primary button reads as part of the button. */
.scope-msg {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin: 0.9rem 0 1.15rem;
  padding: 0.75rem 0.9rem;
  border-radius: 0.7rem;
  font-size: 0.83rem;
  line-height: 1.5;
}
.scope-msg .material-symbols-outlined {
  font-size: 20px;
  flex: none;
  margin-top: 0.05rem;
}
.scope-msg-body {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}
.scope-msg-lead { font-weight: 700; }
/* Not a lighter colour — these sit on tinted fills where a second tone
   turns muddy. Opacity keeps the step consistent across all four themes. */
.scope-msg-detail { opacity: 0.82; }

/* "This will also do X." Nothing is wrong and the button stays live, so
   it borrows the surface + inset primary rule the active nav link uses
   rather than an alarm colour — and the sentence carries the meaning,
   since hue alone never may (RULES §2). */
.scope-warn {
  background: var(--color-surface-container-high);
  color: var(--color-on-surface);
  box-shadow: inset 3px 0 0 var(--color-primary);
}
.scope-warn .material-symbols-outlined { color: var(--color-primary); }

/* "That name is taken." The button beside it is disabled by the same
   script, so the colour is reinforcement, never the only signal. */
.scope-conflict {
  background: color-mix(in srgb, var(--color-error-container) 70%, transparent);
  color: var(--color-on-error-container);
  box-shadow: inset 3px 0 0 var(--color-error);
}
.scope-conflict .material-symbols-outlined { color: var(--color-error); }

/* One section row on the Categories pane: name, where it applies, what's
   filed in it, then its actions. */
.sec-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  padding: 0.6rem 0.2rem;
  border-bottom: 1px dashed var(--color-outline-variant);
}
.sec-row:last-of-type { border-bottom: none; }
.sec-name { font-weight: 700; }
.sec-meta {
  font-size: 0.78rem;
  color: var(--color-on-surface-variant);
  white-space: nowrap;
}
.sec-actions { display: flex; align-items: center; gap: 0.4rem; margin-left: auto; }

/* Nothing to show. Says which filter emptied the list, because "no
   results" over a list the user just filtered is a dead end. */
.proc-empty {
  padding: 1.6rem 0.4rem;
  text-align: center;
  color: var(--color-on-surface-variant);
  font-size: 0.9rem;
}

/* Pager. Whole rows are links, so the current page is a span — a link to
   where you already are is a small lie the keyboard user pays for. */
.proc-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-top: 1rem;
  padding-top: 0.8rem;
  border-top: 1px dashed var(--color-outline-variant);
  font-size: 0.82rem;
  color: var(--color-on-surface-variant);
}
.proc-pager-links { display: flex; gap: 0.3rem; align-items: center; }
.proc-pager-links a,
.proc-pager-links span {
  padding: 0.25rem 0.55rem;
  border-radius: 0.5rem;
  text-decoration: none;
  color: inherit;
  font-variant-numeric: tabular-nums;
}
.proc-pager-links a:hover { background: var(--color-surface-container-low); }
.proc-pager-links .current {
  background: var(--color-primary);
  color: var(--color-on-primary);
  font-weight: 700;
}

@media (max-width: 560px) {
  .proc-toolbar .proc-search,
  .proc-toolbar select { flex: 1 1 100%; }
  .sec-actions { margin-left: 0; width: 100%; }
}

/* ── app nav (signed-in pill bar) ─────────────────────────────── */
.app-nav {
  display: flex;
  gap: 0.25rem;
  max-width: 1000px;
  margin: 0.75rem auto 0;
  padding: 0 1rem;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.app-nav::-webkit-scrollbar { display: none; }
.app-nav-link {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.45rem 0.85rem;
  border-radius: 9999px;
  font-size: 0.85rem;
  font-weight: 700;
  text-decoration: none;
  color: var(--color-on-surface-variant);
  white-space: nowrap;
}
.app-nav-link .material-symbols-outlined { font-size: 18px; }
.app-nav-link:hover { background: var(--color-surface-container); }
.app-nav-link.active {
  background: var(--color-primary);
  color: var(--color-on-primary);
}

/* ── dashboard ────────────────────────────────────────────────── */
.dash-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
  margin-bottom: 1.25rem;
}
@media (max-width: 640px) {
  .dash-stats { grid-template-columns: 1fr; }
}
.dash-stat {
  background: var(--color-surface-container-lowest);
  border-radius: 1.25rem;
  padding: 1.1rem 1.25rem;
  box-shadow: 0 16px 40px color-mix(in srgb, var(--color-on-surface) 6%, transparent);
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.dash-stat-label {
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-on-surface-variant);
}
.dash-stat-value {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--color-primary);
}
.dash-stat-hint { font-size: 0.78rem; color: var(--color-on-surface-variant); }

/* ── day headline: one tile, three readings ───────────────────────
   Earned is what the day is about, so it holds the hero treatment and
   the biggest type. Production and eligible are the same billed work
   measured twice and ride along on the right of the same tile, past a
   hairline — as their own card they left the earned figure with an
   empty right half at desktop widths.

   The gradient is deliberately restated here rather than borrowing the
   dashboard's classes: this page and that one are redesigned
   independently, and the first time the dashboard's hero was renamed
   this tile silently lost its background. Shared LOOK, not shared
   selectors. */
.day-hero {
  position: relative;
  overflow: hidden;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 1.5rem;
  margin-bottom: 1.25rem;
  padding: 1.4rem 1.5rem;
  border-radius: 1.25rem;
  background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dim));
  color: var(--color-on-primary);
  box-shadow: 0 18px 44px color-mix(in srgb, var(--color-primary) 28%, transparent);
}
.day-hero::after {
  /* Soft radial sheen — texture without introducing another colour.
     Kept over the headline half: lightening the green under the two
     small figures would cost their labels contrast. */
  content: "";
  position: absolute;
  top: -75%;
  left: -12%;
  width: 55%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--color-on-primary) 16%, transparent), transparent 70%);
  pointer-events: none;
}
.day-hero > * { position: relative; z-index: 1; }
.day-hero-earned { display: flex; flex-direction: column; gap: 0.15rem; }

/* Hairline, not a panel: the figures are a second reading of the tile's
   own subject, so they stay on its surface.

   Side by side rather than stacked — two short figures in a column left
   the headline with the same wide gap the separate card did, only
   further right. */
.day-hero-figures {
  display: flex;
  gap: 1.4rem;
  padding-left: 1.6rem;
  border-left: 1px solid color-mix(in srgb, var(--color-on-primary) 26%, transparent);
}
.day-hero-figures .day-figure { min-width: 0; }
.day-hero-figures .day-figure + .day-figure {
  padding-left: 1.4rem;
  border-left: 1px solid color-mix(in srgb, var(--color-on-primary) 20%, transparent);
}
@media (max-width: 760px) {
  .day-hero { grid-template-columns: 1fr; gap: 1.1rem; }
  /* Stacked under the headline, the divider turns with it. */
  .day-hero-figures {
    padding: 1.1rem 0 0;
    border-left: 0;
    border-top: 1px solid color-mix(in srgb, var(--color-on-primary) 26%, transparent);
  }
  .day-hero-figures .day-figure { flex: 1; }

  /*  A THIRD figure ("Collected") appears the moment the day carries a
      pay adjustment, and three money columns do not fit a phone. The
      hero clips its overflow, so a row that can't wrap silently loses
      the last figure — which is precisely the one just added.

      A two-column grid instead of a flex row. Two figures still sit side
      by side with their hairline between them; a third drops to its own
      line. :nth-child(odd) is "first in row" here, and a divider at the
      start of a line divides nothing. */
  .day-hero-figures {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 0;
    row-gap: 0.9rem;
  }
  .day-hero-figures .day-figure + .day-figure { margin-left: 1.2rem; }
  .day-hero-figures .day-figure:nth-child(odd) {
    margin-left: 0;
    padding-left: 0;
    border-left: 0;
  }
}

.day-figure { display: flex; flex-direction: column; gap: 0.1rem; }
.day-figure-label {
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* 0.94, same as the tile's own label: measured against the themed
     primaries, small text below this drops under 4.5:1. */
  opacity: 0.94;
}
.day-figure-value {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.5rem;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.day-figure-hint { font-size: 0.78rem; opacity: 0.94; }

.day-earned-label {
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* 0.94 rather than a lighter knock-back: measured against the themed
     primaries, small text below this drops under 4.5:1. */
  opacity: 0.94;
}
.day-earned-value {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: clamp(2.3rem, 5.4vw, 3.1rem);
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  line-height: 1.05;
  margin: 0.1rem 0 0.15rem;
}
.day-earned-hint { font-size: 0.85rem; opacity: 0.94; }
/* Simulated pay on a saturated tile: the struck-through actual and the
   delta chip have to invert, or they render as dark text on dark green. */
.day-hero .sim-money-was { color: inherit; opacity: 0.8; }
.day-hero .sim-money-delta {
  background: color-mix(in srgb, var(--color-on-primary) 22%, transparent);
  color: inherit;
}

/* One clinic per page, so the shared two-column grid would leave the
   clinic card at half width with an empty column beside it. */
.day-clinic-grid { grid-template-columns: 1fr; }
@media (min-width: 720px) {
  .day-clinic-grid { grid-template-columns: 1fr; }
}

/* ── day exports ──────────────────────────────────────────────────
   Three explicit buttons rather than a menu: there are only three, and
   a menu would hide the two that aren't the PDF. */
.pay-clinic-head-end {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.export-bar {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  padding: 0.2rem;
  border-radius: 999px;
  background: var(--color-surface-container-low);
}
.export-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.35rem 0.65rem;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--color-on-surface-variant);
  font-family: inherit;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  cursor: pointer;
  transition: background 140ms ease, color 140ms ease;
}
.export-btn:hover:not(:disabled) {
  background: var(--color-surface-container-lowest);
  color: var(--color-primary);
}
.export-btn:disabled { cursor: default; }
.export-btn .material-symbols-outlined { font-size: 18px; line-height: 1; }

/* Rendering a nine-page report takes a few seconds, and the old busy
   state was `opacity: 0.55` — which reads as "this button is disabled",
   the opposite of what's happening. The format glyph is swapped for a
   spinner in place instead: same footprint, so nothing shifts, and the
   button stays at full strength because it IS working.
   Paired with the status line below; a spinner alone is easy to miss on
   a control this small. */
.export-btn { position: relative; }
.export-btn.is-busy {
  opacity: 1;
  color: var(--color-primary);
  cursor: progress;
}
.export-btn.is-busy .material-symbols-outlined { visibility: hidden; }
.export-btn.is-busy::before {
  content: "";
  position: absolute;
  left: 0.65rem;          /* the button's own padding — lands on the glyph */
  top: 50%;
  width: 0.95rem;
  height: 0.95rem;
  margin-top: -0.475rem;
  border-radius: 50%;
  border: 2px solid color-mix(in srgb, currentColor 28%, transparent);
  border-top-color: currentColor;
  animation: export-spin 0.7s linear infinite;
}
@keyframes export-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  /* Still turning — a frozen ring reads as a broken button — just slowly. */
  .export-btn.is-busy::before { animation-duration: 2.4s; }
}
/* currentColor does the work, so the saturated tile only has to keep its
   own ink rather than restate the spinner. */
.check-settled .export-btn.is-busy { color: inherit; }
@media (max-width: 520px) {
  /* The glyphs carry the meaning once space is tight. */
  .export-btn-text { display: none; }
}

/* The PDF preview dialog is gone — `.export-modal`, `.export-preview`,
   `.export-busy` and `.export-spinner` with it. A 900px modal showing a
   Letter page behind the browser's own 170px thumbnail rail rendered at
   67%, which is not a preview. PDF now downloads like XLS does, and the
   busy state lives on the button (`.export-btn.is-busy`, above). */

/* The bar plus one line to speak from. It carries both states, but only
   the failure is DRAWN — while a render runs the same element goes
   .visually-hidden and exists purely to be announced.

   Progress text used to be visible and it made the page move twice: the
   line appeared, the tile grew taller, then it vanished a few seconds
   later and everything snapped back. The spinner in the button already
   says "working"; the words were only ever for the reader who can't see
   it. A failure earns the shift, because it stays and has to be read. */
.export-group {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.35rem;
  min-width: 0;
}
.export-msg {
  margin: 0;
  max-width: 22rem;
  text-align: right;
  font-size: 0.76rem;
  line-height: 1.4;
  color: var(--color-on-surface-variant);
}
.export-msg.is-error { color: var(--color-error); }
/* On a filled tile the themed error red is unreadable against the
   primary behind it, so the message takes the tile's own ink — which
   would leave it looking like ordinary body copy. A chip gives it back
   the "this is not part of the card" reading, without depending on a hue
   that has to survive ten themes and a black-and-white printout. */
.check-settled .export-msg {
  color: inherit;
  padding: 0.25rem 0.55rem;
  border-radius: 0.5rem;
  background: color-mix(in srgb, var(--color-on-primary) 18%, transparent);
}

/* CSV options */
.csv-field { border: none; padding: 0; margin: 0 0 1.1rem; }
.csv-field legend {
  padding: 0;
  margin-bottom: 0.5rem;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-on-surface-variant);
}
.csv-grain { display: flex; flex-direction: column; gap: 0.4rem; }
.csv-option {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid color-mix(in srgb, var(--color-on-surface) 12%, transparent);
  border-radius: 0.8rem;
  cursor: pointer;
  transition: border-color 140ms ease, background 140ms ease;
}
.csv-option:hover { border-color: color-mix(in srgb, var(--color-primary) 45%, transparent); }
.csv-option:has(input:checked) {
  border-color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 7%, transparent);
}
.csv-option input { margin-top: 0.2rem; accent-color: var(--color-primary); }
.csv-option-body { display: flex; flex-direction: column; gap: 0.1rem; }
.csv-option-title { font-weight: 700; font-size: 0.9rem; }
.csv-option-sub { font-size: 0.78rem; color: var(--color-on-surface-variant); }
.csv-seps { display: flex; gap: 1rem; }
.csv-sep { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.88rem; cursor: pointer; }
.csv-sep input { accent-color: var(--color-primary); }
.csv-hint { margin: 0.45rem 0 0; font-size: 0.78rem; color: var(--color-on-surface-variant); }
.csv-preview-wrap { margin-bottom: 0.25rem; }
.csv-preview-label {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-on-surface-variant);
}
.csv-preview {
  margin: 0;
  padding: 0.7rem 0.8rem;
  max-height: 9rem;
  overflow: auto;
  border-radius: 0.7rem;
  background: var(--color-surface-container-low);
  font-family: ui-monospace, "SFMono-Regular", "Cascadia Mono", Menlo, Consolas, monospace;
  font-size: 0.72rem;
  line-height: 1.6;
  white-space: pre;
  color: var(--color-on-surface-variant);
}

/* ── calendar day report ──────────────────────────────────────── */
.cal-daylink { position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
.cal-cell.worked:hover { outline: 2px solid var(--color-primary); outline-offset: -2px; }
.finalized-pill { background: var(--color-primary-container); color: var(--color-on-primary-container); }
.day-notes {
  margin: 0.6rem 0 0;
  padding: 0.5rem 0.7rem;
  background: var(--color-surface-container-low);
  border-radius: 0.5rem;
  font-size: 0.85rem;
  color: var(--color-on-surface-variant);
  white-space: pre-wrap;
}

/* ── report generation day preview ────────────────────────────── */
.day-preview { margin-top: 0.75rem; }
.day-preview-strip {
  display: flex;
  gap: 0.35rem;
  overflow-x: auto;
  padding-bottom: 0.35rem;
  -webkit-overflow-scrolling: touch;
}
.day-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.1rem;
  min-width: 3.4rem;
  padding: 0.35rem 0.45rem;
  background: var(--color-surface-container-low);
  border-radius: 0.6rem;
  text-decoration: none;
  color: var(--color-on-surface);
  font-size: 0.7rem;
}
.day-chip:hover { background: var(--color-primary-container); }
.day-chip strong { font-variant-numeric: tabular-nums; font-size: 0.75rem; }
.day-preview-totals {
  margin-top: 0.4rem;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--color-on-surface-variant);
}

/* Plan-gate upsell panel */
.gate-panel {
  max-width: 520px;
  margin: 3rem auto;
  text-align: center;
}
@media (max-width: 560px) {
  .gate-panel { margin: 2rem 1rem; }
}
.gate-panel .gate-icon {
  font-size: 40px;
  color: var(--color-outline);
}
.gate-panel p { color: var(--color-on-surface-variant); }

/* Beta-enrolment note on the signup success page — tertiary family so
   it reads as a bonus, distinct from the primary "you're in" chrome. */
.beta-note {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.85rem auto 0;
  padding: 0.5rem 0.9rem;
  background: var(--color-tertiary-container);
  color: var(--color-on-tertiary-container);
  border-radius: 9999px;
  font-size: 0.85rem;
  text-align: left;
}
.beta-note .material-symbols-outlined { font-size: 18px; }

.qr-card {
  text-align: center;
}
.qr-card .qr {
  width: 180px;
  height: 180px;
  margin: 0.5rem auto 0.75rem;
  background: var(--color-surface-container);
  border-radius: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-on-surface-variant);
}
.qr-card .qr svg { width: 90%; height: 90%; }
.store-row {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.75rem;
}
@media (min-width: 480px) {
  .store-row { flex-direction: row; }
  .store-row > a { flex: 1; }
}

/* ───────────────────────── Auth-aware nav links ──────────── */

.topbar .nav-links {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.topbar .nav-link {
  padding: 0.5rem 0.85rem;
  font-family: "Plus Jakarta Sans", sans-serif;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-on-surface);
  border-radius: 9999px;
  text-decoration: none;
  transition: background 120ms ease;
}
.topbar .nav-link:hover { background: var(--color-surface-container); color: var(--color-on-surface); }
.topbar .nav-link.primary {
  background: var(--color-primary);
  color: var(--color-on-primary);
}
.topbar .nav-link.primary:hover { background: var(--color-primary-dim); color: var(--color-on-primary); }

/* The single dominant call-to-action (beta signup). Brand gradient + icon +
   soft shadow so it reads as *the* action and outranks the flat primary pill;
   sits first in the nav, ahead of the secondary text links. */
.topbar .nav-link.nav-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.55rem 1.1rem;
  font-weight: 700;
  color: var(--color-on-primary);
  background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dim));
  box-shadow: 0 8px 22px color-mix(in srgb, var(--color-primary) 32%, transparent);
  transition: transform 150ms ease, box-shadow 150ms ease;
}
.topbar .nav-link.nav-cta .material-symbols-outlined { font-size: 18px; }
.topbar .nav-link.nav-cta:hover {
  color: var(--color-on-primary);
  background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dim));
  transform: translateY(-1px);
  box-shadow: 0 12px 30px color-mix(in srgb, var(--color-primary) 42%, transparent);
}
.topbar .nav-link.nav-cta:focus-visible {
  outline: 2px solid var(--color-primary-dim);
  outline-offset: 2px;
}

/* Thin rule separating the action from the navigation links. */
.topbar .nav-divider {
  width: 1px;
  height: 20px;
  margin: 0 0.35rem;
  background: color-mix(in srgb, var(--color-on-surface) 15%, transparent);
}

/* Fold: keep the CTA, drop the secondary copy and the now-orphaned divider. */
@media (max-width: 480px) {
  .topbar .nav-link.secondary,
  .topbar .nav-divider { display: none; }
}

/* ═══════════════════════════════════════════════════════════════════
   REDESIGN — Split layout, step rail, marketing aside, checkout v2
   ═══════════════════════════════════════════════════════════════════ */

/* ───────────────────────── Wide split shell ─────────────────────── */
/* Two-column shell used by Signup/Index, Verify, and Checkout on
   wide screens. Left = form. Right = marketing/social-proof rail.
   Mobile collapses to single-column with the rail tucked under. */

.auth-split {
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 1rem;
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}
@media (min-width: 960px) {
  .auth-split {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    gap: 2.25rem;
    padding: 0 1.5rem;
  }
}

.auth-aside {
  background: linear-gradient(170deg,
    color-mix(in srgb, var(--color-primary-container) 70%, var(--color-surface-container-lowest)),
    var(--color-surface-container-lowest));
  border-radius: 1.5rem;
  padding: 1.5rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  align-self: start;
}
@media (min-width: 960px) {
  .auth-aside { padding: 2rem 1.75rem; position: sticky; top: 96px; }
}

.auth-aside .aside-eyebrow {
  font-family: "Plus Jakarta Sans", sans-serif;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-on-primary-container);
  opacity: 0.8;
}

.auth-aside h2 {
  margin: 0;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.35rem;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--color-on-surface);
}
@media (min-width: 960px) { .auth-aside h2 { font-size: 1.6rem; } }

.aside-list {
  list-style: none;
  margin: 0.25rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.aside-list li {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--color-on-surface);
}
.aside-list li .material-symbols-outlined {
  font-size: 22px;
  color: var(--color-primary);
  background: var(--color-surface-container-lowest);
  border-radius: 9999px;
  padding: 4px;
  flex: 0 0 auto;
}
.aside-list li strong { display: block; font-weight: 700; color: var(--color-on-surface); }
.aside-list li span.muted { color: var(--color-on-surface-variant); font-size: 0.85rem; }

.aside-quote {
  margin-top: 0.5rem;
  padding: 1rem 1.1rem;
  background: var(--color-surface-container-lowest);
  border-radius: 1rem;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--color-on-surface);
  font-style: italic;
}
.aside-quote cite {
  display: block;
  margin-top: 0.5rem;
  font-style: normal;
  font-weight: 600;
  font-size: 0.78rem;
  color: var(--color-on-surface-variant);
}

.aside-trust {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.25rem;
}
.aside-trust span {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.3rem 0.65rem;
  background: var(--color-surface-container-lowest);
  color: var(--color-on-surface);
  border-radius: 9999px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}
.aside-trust span .material-symbols-outlined {
  font-size: 14px;
  color: var(--color-primary);
}

/* ───────────────────────── Numbered step rail ───────────────────── */
/* Replaces the dot-progress bars on key signup pages with a more
   self-explanatory labelled rail. Mobile keeps the simple bar
   (smaller screens benefit from less chrome); the labelled rail
   appears on tablet+. */

.step-rail {
  display: none;
  margin: 1.25rem 0 0.5rem;
  padding: 0.85rem 1rem;
  background: var(--color-surface-container-low);
  border-radius: 1rem;
}
@media (min-width: 600px) { .step-rail { display: flex; gap: 0.5rem; align-items: center; } }

.step-rail .step-item {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: "Plus Jakarta Sans", sans-serif;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--color-on-surface-variant);
  position: relative;
  min-width: 0;
}
.step-rail .step-item .num {
  width: 24px;
  height: 24px;
  border-radius: 9999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.78rem;
  font-weight: 700;
  background: var(--color-surface-container);
  color: var(--color-on-surface-variant);
  flex: 0 0 auto;
}
.step-rail .step-item .num .material-symbols-outlined { font-size: 16px; }
.step-rail .step-item .label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.step-rail .step-item.done .num    { background: var(--color-primary-dim); color: var(--color-on-primary); }
.step-rail .step-item.done         { color: var(--color-on-surface); }
.step-rail .step-item.active .num  { background: var(--color-primary); color: var(--color-on-primary); }
.step-rail .step-item.active       { color: var(--color-on-surface); }
.step-rail .step-item:not(:last-child)::after {
  content: '';
  flex: 1 1 auto;
  height: 2px;
  background: var(--color-surface-container);
  border-radius: 9999px;
  margin: 0 0.4rem 0 0.65rem;
}
.step-rail .step-item.done:not(:last-child)::after {
  background: var(--color-primary-dim);
}

/* ───────────────────────── Hero copy on auth pages ──────────────── */

.auth-hero-row {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}
.auth-hero-row .micro {
  font-size: 0.78rem;
  color: var(--color-on-surface-variant);
}

/* ───────────────────────── Password strength meter ──────────────── */

.pw-wrap { position: relative; }
.pw-toggle {
  position: absolute;
  top: 50%;
  right: 0.5rem;
  transform: translateY(-50%);
  background: transparent;
  border: none;
  width: 36px;
  height: 36px;
  border-radius: 9999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--color-on-surface-variant);
  cursor: pointer;
}
.pw-toggle:hover { background: var(--color-surface-container); }
.pw-toggle .material-symbols-outlined { font-size: 20px; }

.pw-meter {
  display: flex;
  gap: 0.25rem;
  margin-top: 0.4rem;
}
.pw-meter span {
  flex: 1;
  height: 4px;
  border-radius: 9999px;
  background: var(--color-surface-container);
  transition: background 160ms ease;
}
.pw-meter[data-score="1"] span:nth-child(-n+1) { background: var(--color-error-container); }
.pw-meter[data-score="2"] span:nth-child(-n+2) { background: var(--color-secondary-container); }
.pw-meter[data-score="3"] span:nth-child(-n+3) { background: var(--color-primary-container); }
.pw-meter[data-score="4"] span                  { background: var(--color-primary); }

.pw-hint {
  margin-top: 0.35rem;
  font-size: 0.78rem;
  color: var(--color-on-surface-variant);
}
.pw-hint[data-score="4"] { color: var(--color-primary); font-weight: 600; }
.pw-hint[data-score="1"] { color: var(--color-error); }

/* ───────────────────────── Checkout v2 — left column ────────────── */

.checkout-grid-v2 {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 1rem;
}
@media (min-width: 960px) {
  .checkout-grid-v2 {
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    gap: 2rem;
    padding: 0 1.5rem;
    align-items: start;
  }
}

.checkout-card {
  background: var(--color-surface-container-lowest);
  border-radius: 1.5rem;
  padding: 1.5rem 1.25rem;
  box-shadow: 0 24px 64px color-mix(in srgb, var(--color-on-surface) 8%, transparent);
}
@media (min-width: 600px) { .checkout-card { padding: 2rem 1.75rem; } }

.checkout-card h1 {
  margin: 0.5rem 0 0.25rem;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
@media (min-width: 600px) { .checkout-card h1 { font-size: 1.875rem; } }

.section-title {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1rem;
  letter-spacing: -0.01em;
  margin: 1.5rem 0 0.75rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--color-on-surface);
}
.section-title .material-symbols-outlined {
  font-size: 20px;
  color: var(--color-primary);
}

/* Friendly toggleable card-input group */
.card-fieldset { border: none; padding: 0; margin: 0; }
.card-fieldset.collapsed { display: none; }
.card-stack { display: flex; flex-direction: column; gap: 1rem; }

.card-row-cvv {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
}
@media (min-width: 480px) { .card-row-cvv { grid-template-columns: 2fr 1fr 1fr; } }

.field-with-icon { position: relative; }
.field-with-icon .material-symbols-outlined.left-icon {
  position: absolute;
  top: 50%;
  left: 0.85rem;
  transform: translateY(-50%);
  color: var(--color-on-surface-variant);
  font-size: 20px;
  pointer-events: none;
}
.field-with-icon input { padding-left: 2.5rem !important; }

.card-brand-strip {
  display: flex;
  gap: 0.4rem;
  margin-top: 0.4rem;
  align-items: center;
  flex-wrap: wrap;
}
.card-brand-strip .brand-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.55rem;
  background: var(--color-surface-container);
  border-radius: 0.5rem;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 0.65rem;
  letter-spacing: 0.06em;
  color: var(--color-on-surface-variant);
  text-transform: uppercase;
}
.card-brand-strip .brand-pill.active {
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
}
.card-brand-strip .micro {
  font-size: 0.72rem;
  color: var(--color-on-surface-variant);
}

/* ───────────────────────── Comp card swap-out ───────────────────── */

.comp-banner {
  display: none;
  margin-top: 0.75rem;
  padding: 1.25rem;
  border-radius: 1.25rem;
  background: linear-gradient(135deg,
    var(--color-primary-container),
    color-mix(in srgb, var(--color-primary-container) 60%, var(--color-surface-container-lowest)));
  color: var(--color-on-primary-container);
}
.comp-banner.show { display: flex; gap: 0.85rem; align-items: flex-start; }
.comp-banner .material-symbols-outlined { font-size: 28px; flex: 0 0 auto; }
.comp-banner h3 {
  margin: 0 0 0.25rem;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.05rem;
  color: var(--color-on-primary-container);
}
.comp-banner p { margin: 0; font-size: 0.92rem; line-height: 1.45; }

/* ───────────────────────── Summary card v2 ──────────────────────── */

.summary-card-v2 {
  background: var(--color-surface-container-lowest);
  border-radius: 1.5rem;
  padding: 1.25rem;
  box-shadow: 0 24px 64px color-mix(in srgb, var(--color-on-surface) 6%, transparent);
}
@media (min-width: 960px) {
  .summary-card-v2 { padding: 1.5rem; position: sticky; top: 96px; }
}

.summary-card-v2 .sum-eyebrow {
  font-family: "Plus Jakarta Sans", sans-serif;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-on-surface-variant);
}

.summary-plan {
  margin-top: 0.4rem;
  padding-bottom: 1rem;
  border-bottom: 1px dashed var(--color-outline-variant);
}
.summary-plan .plan-name {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.25rem;
  letter-spacing: -0.01em;
  margin: 0;
}
.summary-plan .plan-cadence {
  margin-top: 0.15rem;
  font-size: 0.85rem;
  color: var(--color-on-surface-variant);
}

.summary-rows {
  margin-top: 0.85rem;
  display: flex;
  flex-direction: column;
}
.summary-rows .row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.5rem 0;
  font-size: 0.92rem;
  color: var(--color-on-surface);
}
.summary-rows .row .lhs { color: var(--color-on-surface-variant); }
.summary-rows .row.discount {
  display: none;
  color: var(--color-primary);
  font-weight: 600;
}
.summary-rows .row.discount.show { display: flex; }
.summary-rows .row.discount .lhs { color: var(--color-primary); }

.summary-total {
  margin-top: 0.4rem;
  padding-top: 0.85rem;
  border-top: 2px solid var(--color-on-surface);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
}
.summary-total .lhs {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1rem;
  color: var(--color-on-surface);
}
.summary-total .rhs {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.15rem;
}
.summary-total .price-now {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
  color: var(--color-on-surface);
  line-height: 1;
}
.summary-total .price-was {
  display: none;
  font-size: 0.85rem;
  color: var(--color-on-surface-variant);
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
}
.summary-total .price-was.show { display: inline; }

.savings-pill {
  display: none;
  margin-top: 0.85rem;
  padding: 0.5rem 0.85rem;
  border-radius: 9999px;
  background: var(--color-primary-container);
  color: var(--color-on-primary-container);
  font-size: 0.85rem;
  font-weight: 700;
  text-align: center;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
}
.savings-pill.show { display: inline-flex; }
.savings-pill .material-symbols-outlined { font-size: 18px; }

.renewal-line {
  margin-top: 0.85rem;
  padding: 0.7rem 0.85rem;
  border-radius: 0.85rem;
  background: var(--color-surface-container-low);
  font-size: 0.8rem;
  color: var(--color-on-surface-variant);
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
  line-height: 1.45;
}
.renewal-line .material-symbols-outlined {
  font-size: 18px;
  color: var(--color-on-surface-variant);
  flex: 0 0 auto;
  margin-top: 1px;
}

/* ───────────────────────── Promo / coupon block ─────────────────── */
/* Always-visible (collapsible coupon fields are conversion killers
   — users alt-tab to Google to find a code and never come back). */

.promo-block {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px dashed var(--color-outline-variant);
}
.promo-label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-family: "Plus Jakarta Sans", sans-serif;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--color-on-surface-variant);
  margin-bottom: 0.45rem;
}
.promo-input-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.5rem;
}
.promo-input-row input {
  width: 100%;
  min-height: 44px;
  padding: 0.65rem 0.85rem;
  font-family: "Manrope", monospace, sans-serif;
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--color-on-surface);
  background: var(--color-surface-container-low);
  border: 1px solid var(--color-outline-variant);
  border-radius: 0.7rem;
  outline: none;
  transition: border-color 120ms ease, box-shadow 120ms ease;
  box-sizing: border-box;
}
.promo-input-row input::placeholder {
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--color-on-surface-variant);
}
.promo-input-row input:focus {
  border-color: var(--color-primary);
  background: var(--color-surface-container-lowest);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 22%, transparent);
}
.promo-input-row input.invalid {
  border-color: var(--color-error);
}
.promo-input-row input.applied {
  border-color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary-container) 50%, var(--color-surface-container-lowest));
}
.promo-action-btn {
  min-height: 44px;
  padding: 0 1rem;
  border-radius: 0.7rem;
  border: 1px solid var(--color-outline-variant);
  background: var(--color-surface-container);
  color: var(--color-on-surface);
  font-family: "Plus Jakarta Sans", sans-serif;
  font-weight: 700;
  font-size: 0.85rem;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.promo-action-btn:hover { background: var(--color-surface-container-high); }
.promo-action-btn.apply {
  background: var(--color-primary);
  color: var(--color-on-primary);
  border-color: var(--color-primary);
}
.promo-action-btn.apply:hover { background: var(--color-primary-dim); }
.promo-action-btn.remove {
  background: transparent;
  border-color: var(--color-error);
  color: var(--color-error);
}
.promo-action-btn[disabled] { opacity: 0.55; cursor: progress; }

.promo-feedback {
  margin-top: 0.4rem;
  font-size: 0.8rem;
  display: flex;
  gap: 0.35rem;
  align-items: flex-start;
  min-height: 1rem;
}
.promo-feedback.error    { color: var(--color-error); }
.promo-feedback.success  { color: var(--color-primary); font-weight: 600; }
.promo-feedback .material-symbols-outlined { font-size: 16px; margin-top: 1px; }

/* ───────────────────────── Trust bar under the CTA ──────────────── */

.trust-bar {
  margin-top: 1rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.85rem 1.25rem;
  font-size: 0.78rem;
  color: var(--color-on-surface-variant);
}
.trust-bar span {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}
.trust-bar span .material-symbols-outlined {
  font-size: 16px;
  color: var(--color-primary);
}

/* ───────────────────────── Plan picker — promise band ───────────── */

.promise-band {
  max-width: 1180px;
  margin: 1.5rem auto 0;
  padding: 1rem 1.25rem;
  background: var(--color-surface-container-lowest);
  border-radius: 1.25rem;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
  text-align: center;
}
@media (min-width: 720px) {
  .promise-band {
    grid-template-columns: repeat(4, 1fr);
    text-align: left;
  }
}
.promise-band .item {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  font-size: 0.85rem;
  color: var(--color-on-surface);
}
.promise-band .item .material-symbols-outlined {
  font-size: 22px;
  color: var(--color-primary);
  flex: 0 0 auto;
}
.promise-band .item strong { display: block; font-weight: 700; }
.promise-band .item span.muted { color: var(--color-on-surface-variant); font-size: 0.78rem; }

/* ───────────────────────── Helpers ──────────────────────────────── */

.text-muted { color: var(--color-on-surface-variant); }
.text-success { color: var(--color-primary); }
.text-error { color: var(--color-error); }
.no-bottom-margin { margin-bottom: 0 !important; }

/* Visually hide while keeping accessible to screen readers */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0);
  white-space: nowrap; border: 0;
}

/* ── day-of-week picker (hourly special-day rates) ─────────────── */
/* Distinct from .day-chip above, which is the report day-preview strip. */
.dow-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.5rem 0 0.75rem;
}
.dow-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 3rem;
  padding: 0.4rem 0.6rem;
  border-radius: 0.6rem;
  background: var(--color-surface-container-low);
  color: var(--color-on-surface-variant);
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
  transition: background 0.15s ease, color 0.15s ease;
}
/* The checkbox drives state but is never seen — clipped rather than
   display:none so it stays keyboard-reachable and screen-reader visible. */
.dow-chip input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  margin: 0;
}
.dow-chip:hover { background: var(--color-primary-container); }
.dow-chip:has(input:checked) {
  background: var(--color-primary);
  color: var(--color-on-primary);
}
.dow-chip:has(input:focus-visible) {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* ── Whole-page pay simulation ────────────────────────────────────
   The riskiest surface in this feature: every money figure is modelled
   but the page otherwise looks exactly like the real one. So the mode is
   announced by a banner that can't be missed, every re-priced figure keeps
   its real value visibly beside it, and the cards carrying modelled money
   take the same hatch as everything else provisional. */

.pay-sim-bar {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin: 0.9rem 0 0;
}
.pay-sim-bar-picker { max-width: 22rem; }
.pay-sim-bar-chips {
  padding: 0.75rem;
  border: 1px dashed var(--color-outline);
  border-radius: 0.75rem;
  background:
    repeating-linear-gradient(
      135deg,
      color-mix(in srgb, var(--color-on-surface) 3.5%, var(--color-surface-container-lowest)) 0 7px,
      var(--color-surface-container-lowest) 7px 14px);
}

/* The page-level "Simulated pay · Show actual pay" banner is gone — it
   repeated the mode picker directly above it and its exit link repeated
   that picker's first option. The mode announcement now rides on the
   picker itself and on the hatch every tile wears; see the note in
   Pages/Pay/Index.cshtml. */

/* A re-priced amount: the real figure stays visible, struck through, so
   the simulated one is always read as a change FROM something rather
   than as the number itself. */
.sim-money { display: inline-flex; align-items: baseline; gap: 0.4rem; flex-wrap: wrap; justify-content: flex-end; }
.sim-money-was {
  font-size: 0.75rem;
  color: var(--color-on-surface-variant);
  text-decoration: line-through;
  font-variant-numeric: tabular-nums;
}
.sim-money-delta {
  font-size: 0.72rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  padding: 0.05rem 0.35rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--color-on-surface) 8%, transparent);
  color: var(--color-on-surface-variant);
}

/* ── Report delete + deletion history ─────────────────────────────
   Two-step: a quiet icon arms the row, then an explicit confirm. The
   destructive button only ever exists in the armed state, so the resting
   list has nothing one mis-click can fire. */

/* The armed state adds a question and two buttons to a row that already
   holds a download. That cannot fit on one line on a narrow card, so the
   cluster wraps — `flex: none` here forced a 489px-tall row and pushed a
   horizontal scrollbar onto the card. */
.report-actions {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 0.35rem;
  max-width: 100%;
}
.report-actions > .btn { flex: none; }

.report-delete-arm {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.4rem 0.55rem;
  color: var(--color-on-surface-variant);
}
.report-delete-arm .material-symbols-outlined { font-size: 17px; }
.report-delete-arm:hover {
  color: var(--color-on-error-container, #690004);
  border-color: color-mix(in srgb, var(--color-error, #b3261e) 45%, transparent);
}

.deletion-log { margin-top: 1.25rem; }
.deletion-log h2 { display: flex; align-items: center; gap: 0.4rem; }
.deletion-log h2 .material-symbols-outlined { font-size: 20px; color: var(--color-on-surface-variant); }
/* Nothing to download here — the rows are history, not documents. */
.deletion-log .row > .label { flex: 1; }

/* ── Delete confirm dialog ────────────────────────────────────────
   Server-rendered from ?confirmDelete=, so it needs no JavaScript: the
   scrim is a link back to the page and Delete is a form post. Replaced an
   inline confirm that had to share a table row with the download button —
   on a narrow card that overflowed and forced a 489px-tall row. */

.del-scrim {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
  background: color-mix(in srgb, var(--color-on-surface) 55%, transparent);
}
/* The scrim itself is the cancel target, sat behind the sheet. */
.del-scrim-hit { position: absolute; inset: 0; display: block; }

.del-modal {
  position: relative;
  z-index: 1;
  width: min(23rem, 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.5rem;
  padding: 1.5rem 1.25rem 1.25rem;
  border-radius: 1.25rem;
  background: var(--color-surface-container-lowest);
  box-shadow: 0 24px 64px color-mix(in srgb, var(--color-on-surface) 28%, transparent);
  animation: del-modal-in 0.18s cubic-bezier(0.2, 0.8, 0.3, 1);
}

@keyframes del-modal-in {
  from { transform: translateY(6px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

.del-icon { font-size: 34px; color: var(--color-error, #b3261e); }

.del-title {
  margin: 0;
  font-family: "Manrope", sans-serif;
  font-size: 1.15rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}

.del-body {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--color-on-surface-variant);
  /* Report titles are long — wrap rather than stretch the sheet. */
  overflow-wrap: anywhere;
}

.del-actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: 100%;
  margin-top: 0.75rem;
}
.del-actions > form { width: 100%; }
.del-actions .btn { width: 100%; justify-content: center; }

/* Cancel is the solid, obvious one — a mistaken click should land here. */
.del-cancel {
  background: var(--color-surface-container);
  border-color: transparent;
  color: var(--color-on-surface);
}

/* Outlined rather than filled: deleting is a real option, but never the
   button a pointer reaches by momentum. */
.del-confirm {
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--color-error, #b3261e) 45%, transparent);
  color: var(--color-error, #b3261e);
}
.del-confirm:hover { background: color-mix(in srgb, var(--color-error, #b3261e) 8%, transparent); }

@media (prefers-reduced-motion: reduce) {
  .del-modal { animation: none; }
}
