/* ============================================================================
   ApiaryId: identity-server UI design system
   ----------------------------------------------------------------------------
   Single-purpose host (auth flows + account management). The design language is
   intentionally restrained: page-centered card, soft shadow instead of borders,
   generous whitespace, one primary action per page. Modeled after the auth UIs
   of Stripe / Vercel / Linear. Pairs with the .detail-* family from Apiary.Admin
   for consistency in vocabulary (.detail-callout etc.) where shared components
   appear (Manage area, Subscriptions/Subscribe).
   ============================================================================ */

:root,
:root[data-theme="light"] {
  --auth-bg: #f7f8fa;
  --auth-card-bg: #ffffff;
  --auth-card-shadow:
    0 1px 1px rgba(15, 23, 42, 0.04),
    0 4px 12px rgba(15, 23, 42, 0.05),
    0 24px 48px -16px rgba(15, 23, 42, 0.08);
  --auth-text: #0f172a;
  --auth-text-muted: #64748b;
  --auth-border: #e2e8f0;
  --auth-divider: #eef0f4;
  --auth-radius: 14px;
  --auth-radius-sm: 8px;
}

/* Theme overrides: each theme is one block of token swaps. Resolved by the inline script
   in _Layout that reads data-theme-pref (Light/Dark/Auto from BrandingContext.Theme),
   maps Auto via prefers-color-scheme, and writes data-theme on <html>. Adding a new theme
   later = one more :root[data-theme="..."] block; no selectors elsewhere change. */
:root[data-theme="dark"] {
  --auth-bg: #0b0f17;
  --auth-card-bg: #131a26;
  --auth-card-shadow:
    0 1px 1px rgba(0, 0, 0, 0.3),
    0 4px 12px rgba(0, 0, 0, 0.25),
    0 24px 48px -16px rgba(0, 0, 0, 0.4);
  --auth-text: #e2e8f0;
  --auth-text-muted: #94a3b8;
  --auth-border: #1f2937;
  --auth-divider: #1a2030;
}

html {
  font-size: 15px;
}

@media (min-width: 768px) {
  html {
    font-size: 16px;
  }
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--auth-bg);
  color: var(--auth-text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
    Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Reset default form margins so inline forms (used as remove-row buttons inside lists)
   don't add unexpected vertical space. */
form {
  margin: 0;
}

/* Page shell: centers the card vertically + horizontally, with breathing
   room on small screens via padding rather than fixed margins. */
.auth-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.auth-shell-main {
  flex: 1 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2.5rem 1rem;
}

/* Each auth page wraps brand + card + (optional) foot in an unclassed <div>. As a flex
   item that wrapper would otherwise shrink-wrap to the card's content, defeating the
   card's max-width. Force it to the auth-card width so the card fills it. */
.auth-shell-main > div {
  width: 100%;
  max-width: 36rem;
}

.auth-shell-main > div:has(.auth-card--wide) {
  max-width: 42rem;
}

/* Operator provenance: the page's footer, rendered on every page, bare layouts included, so it
   carries its own bottom padding. flex-shrink:0 keeps it from being squeezed away on the
   flex-column auth shell; on the block-flow Manage and legal pages it follows the content.
   Deliberately NOT var(--brand-primary): a tenant palette must not be able to paint it. */
.platform-provenance {
  flex-shrink: 0;
  margin: 0;
  padding: 0 1rem 1.75rem;
  text-align: center;
  font-size: 0.75rem;
  color: var(--auth-text-muted);
}

.platform-provenance a {
  color: inherit;
  text-decoration: none;
  font-weight: 500;
}

.platform-provenance a:hover {
  color: var(--auth-text);
}

.platform-provenance-doc {
  margin-left: 0.85rem;
}

/* Wordmark + sub-brand shown above the card, ties pages together. */
.auth-brand {
  text-align: center;
  margin-bottom: 1.25rem;
}

.auth-brand-logo {
  /* The app's logo, which is the whole mark when it has one. There is no letter avatar to share
     geometry with any more, so this is the image's own box rather than an override of a square.
     Height is the constraint and width follows the natural aspect ratio up to the cap; object-fit
     keeps a logo of any proportion undistorted inside it. */
  display: inline-block;
  height: 2.5rem;
  max-width: 9rem;
  object-fit: contain;
}

.auth-brand-name {
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: -0.01em;
  color: var(--auth-text);
}

/* The card. No border, just the shadow. */
.auth-card {
  width: 100%;
  max-width: 36rem;
  background: var(--auth-card-bg);
  border-radius: var(--auth-radius);
  box-shadow: var(--auth-card-shadow);
  padding: 2.5rem 2.75rem;
}

.auth-card--wide {
  max-width: 42rem;
}

.auth-card-header {
  margin-bottom: 1.5rem;
  text-align: center;
}

.auth-card-title {
  margin: 0 0 0.4rem;
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.15;
  color: var(--auth-text);
}

.auth-card-subtitle {
  margin: 0;
  font-size: 0.92rem;
  color: var(--auth-text-muted);
  line-height: 1.5;
}

/* A value the user may need to pass on verbatim: shown whole, wrapped anywhere, never a link. */
.auth-card-detail {
  margin: 0 0 1rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--auth-border);
  border-radius: var(--auth-radius-sm);
  font-family: var(--bs-font-monospace, monospace);
  font-size: 0.85rem;
  color: var(--auth-text);
  overflow-wrap: anywhere;
}

.auth-card-note {
  margin: 0;
  font-size: 0.85rem;
  color: var(--auth-text-muted);
}

/* Form blocks. We rely on Bootstrap's .form-floating for the labels but tighten
   borders, focus rings, and rhythm so it sits in the card cleanly. */
.auth-form .form-floating > .form-control,
.auth-form .form-floating > .form-select {
  height: 3.25rem;
  padding-top: 1.5rem;
  padding-bottom: 0.4rem;
  background: var(--auth-card-bg);
  border: 1px solid var(--auth-border);
  border-radius: var(--auth-radius-sm);
  font-size: 0.95rem;
  color: var(--auth-text);
  transition: border-color 0.12s, box-shadow 0.12s;
}

.auth-form .form-floating > .form-control:focus,
.auth-form .form-floating > .form-select:focus {
  border-color: var(--bs-primary);
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--bs-primary) 16%, transparent);
}

.auth-form .form-floating > label {
  color: var(--auth-text-muted);
  padding: 1rem 0.95rem;
}

.auth-form .form-floating + .form-floating,
.auth-form .auth-form-help + .form-floating {
  margin-top: 0.85rem;
}

/* Country dropdown + national-number input rendered side-by-side. The country side
   sits narrow ("United States (+1)" comfortably fits in ~14ch) so the number field
   gets the visual weight. Stacks vertically on narrow viewports where 14ch + a
   number column would push the input below readable width. */
.auth-form .phone-input-row {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin-top: 0.85rem;
}

.auth-form .phone-input-row + .form-floating,
.auth-form .form-floating + .phone-input-row {
  margin-top: 0.85rem;
}

/* Reset the form-floating+form-floating sibling-margin rule for children of this row.
   Without this override the inline ".phone-input-number { margin-top: 0 }" loses the
   specificity contest against ".auth-form .form-floating + .form-floating" and the
   second column ends up pushed down 0.85rem, visibly misaligned from the country
   column. Scoping under .phone-input-row matches the rule's specificity and wins on
   source order. */
.auth-form .phone-input-row .form-floating {
  margin-top: 0;
}

.auth-form .phone-input-country {
  flex: 0 0 11rem;
}

.auth-form .phone-input-number {
  flex: 1 1 auto;
}

@media (max-width: 480px) {
  .auth-form .phone-input-row {
    flex-direction: column;
  }

  .auth-form .phone-input-country,
  .auth-form .phone-input-number {
    flex: 1 1 auto;
  }

  .auth-form .phone-input-row .form-floating + .form-floating {
    margin-top: 0.85rem;
  }
}

/* asp-validation-summary emits its wrapper whenever ModelState is invalid, including when the
   only errors are property-level and a ModelOnly summary therefore excludes all of them, which is
   what a wrong 2FA code produces. What lands is a <ul> holding just the generator's placeholder
   <li style="display:none">, painted as an empty tinted stripe above the field that is already
   showing the real message. Real error items carry no style attribute, so "no unstyled <li>" is
   exactly "nothing to show", one condition covering the valid and the excluded-errors states
   alike. Keyed on the generator's own classes rather than .auth-form-error: that one is a
   presentational error-box look, and hiding on it would silently blank a hand-authored message. */
:is(.validation-summary-valid, .validation-summary-errors):not(:has(li:not([style]))) {
  display: none;
}

/* asp-validation-for emits its <span> even when valid. */
.auth-form .field-validation-valid {
  display: none;
}

.auth-form-help {
  margin: 0.4rem 0.1rem 0;
  font-size: 0.78rem;
  color: var(--auth-text-muted);
}

.auth-form-help--center {
  text-align: center;
}

/* Detached help text: extra top margin when the help follows a button group / list
   instead of immediately following an input. */
.auth-form-help--detached {
  margin-top: 1rem;
}

/* Inline metadata used as the second line in a list-row, tighter than the form-help
   default since the row already has its own spacing. */
.auth-form-help--inline {
  margin: 0.15rem 0 0;
}

/* Lead-in line introducing the block immediately below it (e.g. "By approving, you'll
   share:" before the consent scopes list). */
.auth-form-help--lead {
  margin-bottom: 0.75rem;
}

/* _TermsAcceptance: underlined so its links read as links inside the label. Never the brand color. */
.auth-terms-acceptance a {
  color: var(--auth-text);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Cloudflare Turnstile sits among full-width rows, but the widget itself is a fixed-size element.
   Center it within the card and reserve its height so the submit button doesn't jump as it loads. */
.auth-turnstile {
  margin-top: 1.1rem;
  display: flex;
  justify-content: center;
  min-height: 65px;
}

.auth-form .form-check {
  margin-top: 0.85rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.88rem;
  color: var(--auth-text);
}

.auth-form .form-check-input {
  margin: 0;
  width: 1.05rem;
  height: 1.05rem;
  border-radius: 0.3rem;
}

.auth-form .field-validation-error,
.auth-form .text-danger {
  display: block;
  margin: 0.3rem 0.1rem 0;
  font-size: 0.78rem;
  color: var(--bs-danger);
}

.auth-form-error {
  margin: 0 0 1rem;
  padding: 0.7rem 0.9rem;
  background: color-mix(in srgb, var(--bs-danger) 7%, var(--auth-card-bg));
  border-left: 3px solid var(--bs-danger);
  border-radius: var(--auth-radius-sm);
  color: var(--auth-text);
  font-size: 0.85rem;
}

/* An error that follows content, rather than leading its form, gets the same 1rem gap above as below. */
* + .auth-form-error {
  margin-top: 1rem;
}

.auth-form-error ul,
.auth-form-error li {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Primary submit + secondary link buttons. */
.auth-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  width: 100%;
  height: 3rem;
  margin-top: 1.4rem;
  padding: 0 1rem;
  background: var(--auth-text);
  color: #fff;
  border: 0;
  border-radius: var(--auth-radius-sm);
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: 0.005em;
  /* Reset the default anchor underline: .auth-btn is used on <a> as well as <button>. */
  text-decoration: none;
  cursor: pointer;
  transition: background 0.12s, transform 0.06s;
}

/* When a button immediately follows a divider, the divider already supplies the visual
   gap. Drop the button's own top margin so the rhythm doesn't double up. */
.auth-divider + .auth-btn {
  margin-top: 0;
}

.auth-btn:hover {
  background: #1f2937;
  color: #fff;
}

.auth-btn:active {
  transform: translateY(1px);
}

.auth-btn:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--bs-primary) 35%, transparent);
  outline-offset: 2px;
}

.auth-btn--primary {
  /* Tenant brand color when set; Bootstrap's primary otherwise. The hover state mixes the
     same value with 8% black so the darken-on-hover effect tracks whichever color is in
     play. No separate hover override per brand needed. */
  background: var(--brand-primary, var(--bs-primary));
}

.auth-btn--primary:hover {
  background: color-mix(in srgb, var(--brand-primary, var(--bs-primary)) 88%, black);
}

.auth-btn--ghost {
  background: transparent;
  color: var(--auth-text);
  border: 1px solid var(--auth-border);
}

.auth-btn--ghost:hover {
  background: var(--auth-bg);
  color: var(--auth-text);
}

.auth-btn--danger {
  background: var(--bs-danger);
}

.auth-btn--danger:hover {
  background: color-mix(in srgb, var(--bs-danger) 88%, black);
}

/* Low-emphasis destructive action: outline + danger tint rather than a solid fill, for
   secondary "cancel my plan" style actions that shouldn't read as the primary CTA. */
.auth-btn--danger-ghost {
  background: transparent;
  color: var(--bs-danger);
  border: 1px solid color-mix(in srgb, var(--bs-danger) 35%, var(--auth-border));
}

.auth-btn--danger-ghost:hover {
  background: color-mix(in srgb, var(--bs-danger) 8%, var(--auth-card-bg));
  border-color: var(--bs-danger);
  color: var(--bs-danger);
}

.auth-btn[disabled] {
  background: var(--auth-divider);
  color: var(--auth-text-muted);
  cursor: not-allowed;
}

/* Side-by-side action row when a page has two equal-weight actions (e.g.
   consent: Cancel / Continue). */
.auth-actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
  margin-top: 1.4rem;
}

.auth-actions .auth-btn {
  margin-top: 0;
}

/* Divider between primary form and external/social options. */
.auth-divider {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  margin: 1.5rem 0;
  color: var(--auth-text-muted);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--auth-divider);
}

/* Card-bottom links and footer prompt ("Don't have an account? Sign up"). */
.auth-card-foot {
  margin-top: 1.5rem;
  text-align: center;
  font-size: 0.88rem;
  color: var(--auth-text-muted);
}

/* Consecutive feet read as one group of escape hatches. Without this each keeps its own 1.5rem
   top margin and they stack 3rem apart. */
.auth-card-foot + .auth-card-foot {
  margin-top: 0.4rem;
}

.auth-card-foot a,
.auth-card-foot button.auth-link-button {
  color: var(--auth-text);
  text-decoration: none;
  font-weight: 500;
}

.auth-card-foot a:hover,
.auth-card-foot button.auth-link-button:hover {
  text-decoration: underline;
}

/* Submit button styled as an inline link, used when an action that semantically belongs
   in the footer (e.g. sign-out + redirect) needs to POST for CSRF safety. */
.auth-card-foot button.auth-link-button {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  /* Restated after the shorthand, which resets it: the button reads at the weight of the links beside it. */
  font-weight: 500;
  cursor: pointer;
}

.auth-card-foot-row {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

/* Status / informational icon at the top of confirmation pages. */
.auth-card-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  margin: 0 auto 1rem;
  border-radius: 50%;
  background: color-mix(in srgb, var(--bs-success) 14%, var(--auth-card-bg));
  color: var(--bs-success);
  font-size: 1.25rem;
}

.auth-card-icon--danger {
  background: color-mix(in srgb, var(--bs-danger) 14%, var(--auth-card-bg));
  color: var(--bs-danger);
}

.auth-card-icon--warning {
  background: color-mix(in srgb, var(--bs-warning) 16%, var(--auth-card-bg));
  color: color-mix(in srgb, var(--bs-warning) 40%, var(--auth-text));
}

.auth-card-icon--info {
  background: color-mix(in srgb, var(--bs-primary) 12%, var(--auth-card-bg));
  color: var(--bs-primary);
}

/* External-provider buttons (Google / GitHub / etc.). Stacked. The generic button is
   monochrome; Google overrides below to meet its Sign-In branding guidelines. */
.auth-providers {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

/* Method chooser (Enroll2fa, LoginWith2fa): one button per option, with any explanatory line
   below and *outside* the button. .auth-btn is a fixed 3rem row that centers its children in a
   line, so a description nested inside one lands beside the label rather than under it and
   spills past the height; kept out here it's free to wrap. Zeroing the button's own margin
   (like .auth-actions does) leaves this gap as the only source of vertical rhythm. An option is
   either a bare .auth-btn (LoginWith2fa, label only) or an .auth-choice wrapping one with its
   caption. The gap separates options, so a described option has to be a single flex item. That
   wrapper needs no rules of its own; it carries a class anyway because .auth-shell-main > div
   already shows what unnamed structure costs once something does need to select it. */
.auth-choices {
  display: flex;
  flex-direction: column;
  gap: 1.35rem;
  margin-top: 1.5rem;
}

.auth-choices .auth-btn {
  margin-top: 0;
}

.auth-provider {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  width: 100%;
  height: 2.85rem;
  padding: 0 1rem;
  background: var(--auth-card-bg);
  color: var(--auth-text);
  border: 1px solid var(--auth-border);
  border-radius: var(--auth-radius-sm);
  font-size: 0.92rem;
  font-weight: 500;
  cursor: pointer;
  transition: border-color 0.12s, background 0.12s;
}

.auth-provider:hover {
  border-color: color-mix(in srgb, var(--auth-text) 25%, var(--auth-border));
  color: var(--auth-text);
}

/* "Sign in with Google": follows Google's Sign-In branding guidelines. The colored "G"
   mark is unaltered and identical across themes; only the button surface, 1px stroke, and
   label color swap between light/dark (Google's prescribed values). Kept full-width to sit
   with the other stacked providers, with the mark + Roboto Medium label centered as a group
   (matching the magic-link / passkey buttons) and spaced by the base provider button's gap. */
.auth-provider--google {
  position: relative;
  overflow: hidden;
  background: #ffffff;
  border-color: #747775;
  color: #1f1f1f;
  font-family: "Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.25px;
  transition: background-color 0.218s, border-color 0.218s, box-shadow 0.218s;
}

.auth-provider-google-icon {
  display: inline-flex;
  align-items: center;
}

/* Logo + label ride above the hover/active state layer so the mark stays crisp. Both are
   relatively positioned for the z-index; the icon stays in normal flow so the base button's
   flex gap supplies the spacing between the mark and the label. */
.auth-provider-google-icon,
.auth-provider-google-label {
  position: relative;
  z-index: 1;
}

/* Google's state layer: a translucent overlay that darkens the surface on hover/active
   (white in dark theme). Sits below the logo + label so only the background tints. */
.auth-provider--google::after {
  content: "";
  position: absolute;
  inset: 0;
  background: #1f1f1f;
  opacity: 0;
  transition: opacity 0.218s;
  pointer-events: none;
}

.auth-provider--google:hover {
  background: #ffffff;
  border-color: #747775;
  color: #1f1f1f;
  box-shadow:
    0 1px 2px 0 rgba(60, 64, 67, 0.3),
    0 1px 3px 1px rgba(60, 64, 67, 0.15);
}

.auth-provider--google:hover::after {
  opacity: 0.08;
}

.auth-provider--google:active::after {
  opacity: 0.12;
}

:root[data-theme="dark"] .auth-provider--google,
:root[data-theme="dark"] .auth-provider--google:hover {
  background: #131314;
  border-color: #8e918f;
  color: #e3e3e3;
}

:root[data-theme="dark"] .auth-provider--google::after {
  background: #ffffff;
}

/* Consent-page detail blocks. */

/* The requesting app's own links (website / privacy / terms), shown as a muted line under
   the consent title. The page is already white-labeled to the app via _AuthBrand, so this
   page deliberately has no second app logo/name block. These reference links are all the
   extra app context the screen needs. Middot separators sit between adjacent links only. */
.auth-consent-links {
  margin: 0.6rem 0 0;
  text-align: center;
  font-size: 0.8rem;
  color: var(--auth-text-muted);
}

.auth-consent-links a {
  color: inherit;
  text-decoration: none;
  white-space: nowrap;
}

.auth-consent-links a:hover {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.auth-consent-links a + a::before {
  content: "·";
  margin: 0 0.55rem;
  color: var(--auth-text-muted);
  text-decoration: none;
}

/* Where continuing sends the browser. Sits directly under the title because it is the one piece
   of identity on this page the requesting app cannot supply for itself. See
   docs/app-impersonation.md. Deliberately NOT styled as a warning: it is shown on every consent
   screen, and a caution treatment that fires every time is one people stop reading. The host is
   the only emphasized text so the eye lands on the part worth comparing to the address bar. */
.auth-consent-destination {
  margin: 0.7rem 0 0;
  text-align: center;
  font-size: 0.8rem;
  color: var(--auth-text-muted);
}

.auth-consent-destination strong {
  font-weight: 500;
  color: var(--auth-text);
  /* Hosts are the one thing here a user reads character by character, so keep them unbroken and
     let a long one scroll its own line rather than wrapping mid-domain, which is exactly how a
     lookalike slips past. */
  white-space: nowrap;
}

.auth-consent-destination i {
  margin-right: 0.35rem;
  opacity: 0.75;
}

.auth-consent-scopes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.auth-consent-scope {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  padding: 0.65rem 0;
  border-bottom: 1px solid var(--auth-divider);
  font-size: 0.9rem;
  color: var(--auth-text);
}

.auth-consent-scope:last-child {
  border-bottom: 0;
}

.auth-consent-scope-icon {
  flex-shrink: 0;
  width: 1.2rem;
  text-align: center;
  margin-top: 0.18rem;
  color: var(--auth-text-muted);
}

/* A flex item's min-width defaults to its content, so without this a scope value with no break
   opportunity (the label falls back to it) widens the page instead of wrapping. */
.auth-consent-scope-body {
  min-width: 0;
}

.auth-consent-scope-body strong {
  display: block;
  font-weight: 500;
  color: var(--auth-text);
  overflow-wrap: anywhere;
}

.auth-consent-scope-body span {
  display: block;
  font-size: 0.8rem;
  color: var(--auth-text-muted);
  overflow-wrap: anywhere;
}

/* Manage area layout: card + sidebar nav, same shadow language. The shell caps at a
   consistent desktop width so the content card lands on the same width on every page
   (~37rem of content inside the card padding). Page-to-page navigation never "jumps"
   wider or narrower based on what each page is showing. A sparse form page (Email) and a
   full list page (Devices) fill the same column. */
.manage-shell {
  /* width:100% is load-bearing: the manage layout renders directly inside the flex-column
     `body.auth-shell` (BareLayout), where the `auto` side-margins below would otherwise make
     this flex item SHRINK-WRAP to its content, so a sparse page (Email) rendered ~600px and a
     dense one (Personal data) ~890px, and the max-width never bound. A definite width makes it
     stretch to max-width on every page, so all Manage pages land on one consistent width. */
  width: 100%;
  max-width: 60rem;
  margin: 2.5rem auto;
  padding: 0 1rem;
}

.manage-grid {
  display: grid;
  grid-template-columns: 14rem minmax(0, 1fr);
  gap: 1.5rem;
}

@media (max-width: 768px) {
  .manage-grid {
    grid-template-columns: 1fr;
  }
}

.manage-nav {
  background: var(--auth-card-bg);
  border-radius: var(--auth-radius);
  box-shadow: var(--auth-card-shadow);
  padding: 0.6rem;
  align-self: flex-start;
  position: sticky;
  top: 1.25rem;
}

.manage-nav .nav {
  flex-direction: column;
}

.manage-nav .nav-link {
  display: block;
  padding: 0.55rem 0.85rem;
  border-radius: var(--auth-radius-sm);
  color: var(--auth-text-muted);
  font-size: 0.9rem;
  text-decoration: none;
  transition: background 0.12s, color 0.12s;
}

.manage-nav .nav-link:hover {
  background: var(--auth-bg);
  color: var(--auth-text);
}

.manage-nav .nav-link.active {
  /* Text color pairs with the bg via --auth-card-bg, not a hardcoded white. Both tokens
     flip inversely between light and dark themes, so the active link stays high-contrast
     in both. A hardcoded #fff would put white text on a light surface in dark mode. */
  background: var(--auth-text);
  color: var(--auth-card-bg);
  font-weight: 500;
}

/* Nav-as-disclosure (see Manage/_Layout). Desktop: the <details> is forced open by script and
   the summary bar is hidden, so this is a no-op and the sidebar renders as always. The collapse
   only engages at the mobile breakpoint below. Strip the default disclosure triangle in both
   the standards and -webkit forms. */
.manage-nav-toggle {
  display: none;
  list-style: none;
}

.manage-nav-toggle::-webkit-details-marker {
  display: none;
}

@media (max-width: 768px) {
  /* The aside is now just the card around the disclosure. The summary and body carry their
     own padding, and sticky positioning isn't wanted for a collapsed bar. */
  .manage-nav {
    position: static;
    padding: 0;
  }

  .manage-nav-toggle {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.9rem 1rem;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--auth-text);
    cursor: pointer;
    user-select: none;
  }

  .manage-nav-toggle .fa-bars {
    font-size: 0.9rem;
    color: var(--auth-text-muted);
  }

  .manage-nav-toggle-label {
    flex: 1;
  }

  .manage-nav-caret {
    font-size: 0.8rem;
    color: var(--auth-text-muted);
    transition: transform 0.15s ease;
  }

  .manage-nav-disclosure[open] .manage-nav-caret {
    transform: rotate(180deg);
  }

  /* Body is hidden by the native <details> when collapsed; when open, this hairline separates
     it from the summary bar and restores the pill-list breathing room the aside padding gave. */
  .manage-nav-body {
    padding: 0.3rem 0.6rem 0.6rem;
    border-top: 1px solid var(--auth-divider);
  }
}

/* Sign-out button at the bottom of the nav. Separated from the page links by a hairline
   so it reads as a distinct action rather than another navigation choice. The form
   wrapper itself carries the divider; the inner button reuses .nav-link styling. */
.manage-nav-signout {
  margin-top: 0.4rem;
  padding-top: 0.4rem;
  border-top: 1px solid var(--auth-divider);
}

.manage-nav-signout-btn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 0.55rem;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  font: inherit;
}

.manage-nav-signout-btn .fa-solid,
.manage-nav-signout-btn .fas {
  font-size: 0.78rem;
  opacity: 0.7;
}

/* Deep-link return: slots in at the top of the nav when the user arrived from an RP.
   Wrapper div carries the divider (mirrors sign-out's form-wraps-button pattern, just
   inverted: bottom border instead of top), so the return action reads as a distinct
   "frame" affordance alongside sign-out rather than another page link. */
.manage-nav-return {
  margin-bottom: 0.4rem;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid var(--auth-divider);
}

.manage-nav-return-link {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
}

.manage-nav-return-link .fa-solid,
.manage-nav-return-link .fas {
  font-size: 0.78rem;
  opacity: 0.7;
}

.manage-content {
  background: var(--auth-card-bg);
  border-radius: var(--auth-radius);
  box-shadow: var(--auth-card-shadow);
  padding: 2.5rem 2.75rem;
  min-width: 0;
}

/* Page title inside the content card. Carries the 1.5rem that the shell header's "Account
   settings" line used to hold: the brand lockup replaced that header, so the per-page h1 is
   now the top of the type hierarchy and has to outrank the h2/h3 section headings below it.
   Without this, a page title and its own subsections render at the same 1.2rem and read as
   peers. Same scale as .auth-card-title, so a Manage title and an auth card title match. */
.manage-content h1 {
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.15;
  margin: 0 0 0.4rem;
}

.manage-content h3,
.manage-content h2 {
  font-size: 1.2rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 0.4rem;
}

.manage-section-help {
  margin: 0 0 1.5rem;
  font-size: 0.88rem;
  color: var(--auth-text-muted);
  max-width: 60ch;
}

/* A form straight under the title, with no help line between, keeps the help line's gap. */
.manage-content h1 + .manage-form {
  margin-top: 1.5rem;
}

/* Separates a secondary group (e.g. "Available upgrades") from the primary list above it. */
.manage-subsection {
  margin-top: 2rem;
}

.manage-subsection-title {
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 0.4rem;
}

/* Forms inside the Manage content card fill the card's inner width, matching the list
   rows (.manage-list) so form pages and list pages land on the same content width. The
   card is the single source of truth for width. Individual forms that read better narrow
   (e.g. the inline add-passkey block) cap themselves locally. */
.manage-form {
  max-width: 100%;
}

/* Sub-section divider used by pages with multiple sections inside one card.
   The --danger modifier forces the same divider even when the section is the
   only .manage-section on the page (e.g. the Delete-account zone at the
   bottom of Connected apps, where the preceding content is a bare list).
   The --detached modifier does the same for the FIRST section on a page that
   has non-section content above it (e.g. TwoFactorAuthentication, where the
   global Enable/Disable buttons sit above the per-factor sections). */
.manage-section + .manage-section,
.manage-section--detached,
.manage-section--danger {
  margin-top: 2.25rem;
  padding-top: 2rem;
  border-top: 1px solid var(--auth-divider);
}

/* Smaller heading that groups items inside a single section, e.g. the
   "This app" / "Other apps" splits inside Connected apps. */
.manage-subsection-heading {
  margin: 1.5rem 0 0.6rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--auth-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.manage-subsection-heading:first-of-type {
  margin-top: 0;
}

/* Numbered step list: the authenticator-pairing wizard on Manage/Authenticator and Enroll2fa. */
.manage-steps {
  /* The gutter the numbered badge sits in. Named because the auth-card variant below has to
     cancel it exactly; a second literal would silently mis-align if this one ever moved. */
  --step-gutter: 2.5rem;
  list-style: none;
  counter-reset: manage-step;
  padding: 0;
  margin: 1.5rem 0 0;
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
}

.manage-steps > li {
  position: relative;
  padding-left: var(--step-gutter);
  counter-increment: manage-step;
}

.manage-steps > li::before {
  content: counter(manage-step);
  position: absolute;
  left: 0;
  top: 0;
  width: 1.75rem;
  height: 1.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--auth-text);
  color: #fff;
  border-radius: 50%;
  font-size: 0.85rem;
  font-weight: 600;
}

.manage-steps h4 {
  margin: 0 0 0.4rem;
  font-size: 1rem;
  font-weight: 600;
  color: var(--auth-text);
}

.manage-steps p {
  margin: 0 0 0.75rem;
  font-size: 0.9rem;
  color: var(--auth-text-muted);
}

.manage-steps a {
  color: var(--auth-text);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* The step list is left-aligned prose hanging off a numbered gutter, which reads fine in the
   wide left-aligned Manage column it was built for. Inside the narrow, centre-aligned auth card
   (Enroll2fa) the gutter pushes the step's *blocks* (QR, secret key, verify form) right of the
   centred header above them, which at phone widths is most of the card. Let those break out of
   the gutter so they centre on the card and get its full inner width; the prose stays indented
   under its number. Scoped to .auth-card, which the Manage page has no part of. */
.auth-card .manage-steps > li > :is(.manage-qrcode, .manage-secret-key, .auth-form) {
  margin-left: calc(var(--step-gutter) * -1);
}

/* Authenticator secret block: copy-friendly monospace token. */
.manage-secret-key {
  margin: 0.75rem 0;
  padding: 0.7rem 0.95rem;
  background: var(--auth-bg);
  border-radius: var(--auth-radius-sm);
  text-align: center;
  font-size: 0.95rem;
}

.manage-secret-key kbd {
  background: transparent;
  color: var(--auth-text);
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  letter-spacing: 0.08em;
  padding: 0;
  user-select: all;
}

.manage-qrcode {
  display: flex;
  justify-content: center;
  /* qr.js paints on window.load, into an empty box. Reserve the finished size (180px canvas plus
     the img's 0.5rem padding either side) so the blocks below don't jump when it lands. The QR
     now leads its step, so everything after it would move. Same reasoning as .auth-turnstile. */
  min-height: 196px;
  margin: 0.5rem 0 1rem;
}

.manage-qrcode img {
  border-radius: var(--auth-radius-sm);
  background: #fff;
  padding: 0.5rem;
}

/* Inline list of recovery codes: monospace grid. */
.recovery-codes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 0.5rem;
  margin: 1rem 0;
  padding: 1rem 1.25rem;
  background: var(--auth-bg);
  border-radius: var(--auth-radius-sm);
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.9rem;
  letter-spacing: 0.04em;
  color: var(--auth-text);
}

.recovery-codes code {
  background: transparent;
  /* Bootstrap gives bare <code> its own pink, which silently beat the block's own colour above
     and left the codes reading as inline code samples rather than a credential to copy down. */
  color: inherit;
  padding: 0;
  user-select: all;
}

/* Listing of connected external providers / data items. */
.manage-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0;
  list-style: none;
}

.manage-list-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.8rem 1rem;
  background: var(--auth-bg);
  border-radius: var(--auth-radius-sm);
  font-size: 0.9rem;
}

.manage-list-row strong {
  color: var(--auth-text);
}

.manage-list-tag {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  background: var(--auth-card-bg);
  border: 1px solid var(--auth-border);
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--auth-text-muted);
}

/* Multi-line variant of .manage-list-row: name + meta line + chips stacked on the left,
   action button top-aligned on the right (used by Connected apps; reusable anywhere a
   list row needs more than one line of content). */
.manage-list-row--stack {
  align-items: flex-start;
}

.manage-list-stack {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 0;
  flex: 1;
}

/* Right-hand action cluster for a .manage-list-row--stack. Each action is its own <form>, so without
   this they stack as block elements and the row grows a second line, which bites with one form as
   readily as with several, and Devices now carries exactly one (Revoke). flex-shrink: 0 keeps them
   from being squeezed by a long device label in .manage-list-stack. */
.manage-list-actions {
  display: flex;
  align-items: flex-start;
  gap: 0.4rem;
  flex-shrink: 0;
}

/* Generic chip row: wraps any inline tags (.manage-list-tag, etc.) with consistent
   spacing. Reusable wherever a horizontal collection of small tags appears. */
.tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-top: 0.15rem;
}

/* Status toast (success / error confirmation) shown above forms. */
.status-message {
  margin: 0 0 1rem;
  padding: 0.7rem 0.9rem;
  border-radius: var(--auth-radius-sm);
  font-size: 0.85rem;
  border-left: 3px solid var(--bs-success);
  background: color-mix(in srgb, var(--bs-success) 7%, var(--auth-card-bg));
  color: var(--auth-text);
}

.status-message--error {
  border-left-color: var(--bs-danger);
  background: color-mix(in srgb, var(--bs-danger) 7%, var(--auth-card-bg));
}

.status-message--warning {
  border-left-color: var(--bs-warning);
  background: color-mix(in srgb, var(--bs-warning) 10%, var(--auth-card-bg));
}

.status-message--info {
  border-left-color: var(--bs-primary);
  background: color-mix(in srgb, var(--bs-primary) 6%, var(--auth-card-bg));
}

.status-message strong {
  display: block;
  margin-bottom: 0.15rem;
  color: var(--auth-text);
}

.status-message p {
  margin: 0;
}

.status-message a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Inline action row inside Manage pages: multiple equally-sized "ghost" links
   that read as actions ("Disable 2FA", "Generate new codes"). */
.manage-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1rem 0 0;
}

.manage-action {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.5rem 0.85rem;
  background: var(--auth-card-bg);
  color: var(--auth-text);
  border: 1px solid var(--auth-border);
  border-radius: var(--auth-radius-sm);
  font-size: 0.85rem;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 0.12s, background 0.12s;
}

.manage-action:hover {
  border-color: color-mix(in srgb, var(--auth-text) 25%, var(--auth-border));
  background: var(--auth-bg);
  color: var(--auth-text);
}

/* Shown-but-unavailable: an action the page deliberately keeps visible so the reason it can't
   run has somewhere to sit (e.g. removing an account's only sign-in method). Overrides the
   variant colors below, and the :hover rules (which browsers still apply to a disabled
   button), so it can't look live. */
.manage-action:disabled,
.manage-action:disabled:hover {
  background: var(--auth-card-bg);
  border-color: var(--auth-border);
  color: var(--auth-text-muted);
  cursor: not-allowed;
  opacity: 0.65;
}

.manage-action--primary {
  /* See .manage-nav .nav-link.active for the rationale on pairing --auth-text bg with
     --auth-card-bg text. Same theme-flipping requirement. */
  background: var(--auth-text);
  border-color: var(--auth-text);
  color: var(--auth-card-bg);
}

.manage-action--primary:hover {
  /* Subtle desaturation toward card-bg gives hover feedback in both themes:
     light mode (#0f172a → slightly lighter), dark mode (#e2e8f0 → slightly darker).
     Matches the direction of the default .manage-action:hover which also brightens
     toward auth-bg. */
  background: color-mix(in srgb, var(--auth-text) 88%, var(--auth-card-bg));
  border-color: color-mix(in srgb, var(--auth-text) 88%, var(--auth-card-bg));
  color: var(--auth-card-bg);
}

.manage-action--danger {
  border-color: color-mix(in srgb, var(--bs-danger) 35%, var(--auth-border));
  color: var(--bs-danger);
}

.manage-action--danger:hover {
  background: color-mix(in srgb, var(--bs-danger) 8%, #fff);
  border-color: var(--bs-danger);
  color: var(--bs-danger);
}

/* Subscribe / Cancel: auth-card transactional flows. The plan picker (Subscribe) and the
   confirm summary (Subscribe confirmation step + Cancel) share these classes; sized to fit
   auth-card--wide (42rem) with comfortable tap targets on touch devices. */
.subscribe-plans {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin: 0.4rem 0 0;
}

/* Section header for a named plan group: one ladder per group when a workspace sells more
   than one product. The default (unnamed) group renders no header, so single-product tenants
   never see one. */
.subscribe-plan-group {
  margin: 0.9rem 0 0;
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--auth-text-muted);
}

.subscribe-plan-group:first-child {
  margin-top: 0;
}

.subscribe-plan {
  display: flex;
  gap: 0.85rem;
  align-items: flex-start;
  padding: 0.95rem 1.1rem;
  background: var(--auth-card-bg);
  border: 1px solid var(--auth-border);
  border-radius: var(--auth-radius-sm);
  cursor: pointer;
  transition: border-color 0.12s, background 0.12s;
}

.subscribe-plan:hover {
  border-color: color-mix(in srgb, var(--brand-primary, var(--bs-primary)) 40%, var(--auth-border));
}

/* `:has(:checked)` lights the selected row in the app's primary color so the radio's state
   reads from the card border, not just the tiny native control - and matches the Subscribe
   button beneath it rather than the house blue. */
.subscribe-plan:has(input:checked) {
  border-color: var(--brand-primary, var(--bs-primary));
  background: color-mix(in srgb, var(--brand-primary, var(--bs-primary)) 5%, var(--auth-card-bg));
}

.subscribe-plan-radio {
  margin-top: 0.3rem;
  accent-color: var(--brand-primary, var(--bs-primary));
}

.subscribe-plan-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 0;
}

.subscribe-plan-head {
  display: flex;
  align-items: baseline;
  gap: 0.65rem;
  flex-wrap: wrap;
}

.subscribe-plan-name {
  font-weight: 600;
  color: var(--auth-text);
}

.subscribe-plan-badge {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  background: color-mix(in srgb, var(--bs-success) 14%, var(--auth-card-bg));
  color: color-mix(in srgb, var(--bs-success) 75%, var(--auth-text));
  border-radius: 999px;
}

/* Neutral variant for a scheduled-cancellation cue ("Ends MMM d"). The green success tint
   would misread as a good state, so this one is muted. The muted ink is darkened toward the text
   token because the plain one sits under 4.5:1 on --auth-bg. */
.subscribe-plan-badge--ending {
  background: var(--auth-bg);
  color: color-mix(in srgb, var(--auth-text-muted) 80%, var(--auth-text));
  border: 1px solid var(--auth-border);
}

/* A held plan Stripe has paused or can't collect for ("Paused" / "Payment failed"), wherever it is
   tagged. It grants nothing until it's paid, so it takes the warning tint rather than "Current"'s
   success one. */
.subscribe-plan-badge--lapsed,
.manage-list-tag--lapsed {
  background: color-mix(in srgb, var(--bs-warning) 18%, var(--auth-card-bg));
  border-color: color-mix(in srgb, var(--bs-warning) 40%, var(--auth-card-bg));
  color: color-mix(in srgb, var(--bs-warning) 40%, var(--auth-text));
}

/* "Monthly only" / "Annual only" states a pricing fact, not a membership status like the two
   above. The success tint would read as a benefit, so it is quieter still: no fill, just the
   muted label, so it sits beside a plan name without competing with "Current". */
.subscribe-plan-badge--cadence {
  background: none;
  color: var(--auth-text-muted);
  padding-inline: 0;
  letter-spacing: 0.04em;
}

/* A card can carry both cadences' prices, and they travel as one unit pushed to the right edge.
   The auto margin lives on this wrapper, not on the first price: with it on the price itself, that
   first span ate every pixel of free space on the line, leaving no room for its partner, which then
   wrapped to a second line and, having no auto margin of its own, sat flush LEFT under the plan
   name. Monthly top-right, annual bottom-left, for any name long enough to make the pair not fit. */
.subscribe-plan-prices {
  margin-left: auto;
  display: flex;
  align-items: baseline;
  gap: 0.55rem;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.subscribe-plan-price {
  font-weight: 600;
  color: var(--auth-text);
  white-space: nowrap;
}

.subscribe-plan-price--alt {
  font-weight: 400;
  color: var(--auth-text-muted);
}

/* "Save 16%" inside the annual price: the success tint of .subscribe-plan-badge, since it is a
   benefit. It dims with its price when monthly is the selected cadence, so the emphasis the toggle
   moves stays on one line. Only the fill drops; the ink keeps 4.5:1. */
.subscribe-plan-save {
  margin-left: 0.15rem;
  padding: 0.05rem 0.45rem;
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  vertical-align: middle;
  background: color-mix(in srgb, var(--bs-success) 14%, var(--auth-card-bg));
  color: color-mix(in srgb, var(--bs-success) 75%, var(--auth-text));
  border-radius: 999px;
}

.subscribe-plan-price--alt .subscribe-plan-save {
  background: none;
}

/* Billing-frequency toggle: a small segmented pair above the plan ladder, rendered only when
   the offer actually spans two cadences. Plain radios underneath, so it posts without JS. */
.subscribe-interval-toggle {
  display: flex;
  width: fit-content;
  gap: 0.25rem;
  margin: 0.4rem auto 0;
  padding: 0.25rem;
  border: 1px solid var(--auth-border);
  border-radius: 999px;
  background: var(--auth-bg);
}

.subscribe-interval-option {
  display: inline-flex;
  align-items: center;
  padding: 0.3rem 0.95rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--auth-text-muted);
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}

.subscribe-interval-option:has(input:checked) {
  background: var(--auth-card-bg);
  color: var(--auth-text);
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.1);
}

/* The native radio stays in the tab order and announces itself; the pill is the visual. */
.subscribe-interval-radio {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.subscribe-interval-option:has(input:focus-visible) {
  outline: 2px solid var(--bs-primary);
  outline-offset: 1px;
}

.subscribe-plan-desc {
  font-size: 0.85rem;
  color: var(--auth-text-muted);
  line-height: 1.45;
  /* Honor line breaks the admin typed in the plan description so a multi-line marketing
     blurb (or hand-typed "- feature" lines) renders as written, not collapsed to one line.
     Razor still HTML-escapes the value, so this adds no injection surface. */
  white-space: pre-line;
}

/* The price a tracking plan moves this subscriber to at their next renewal. Their workspace is
   merchant of record and apiaryID sends no price notice, so this line is the only place they learn
   it before the charge. Muted like the description, but no pre-line: this is our sentence, not the
   admin's typed blurb. */
.subscribe-plan-pending {
  font-size: 0.85rem;
  /* Full-strength text, unlike the muted .subscribe-plan-desc directly below it: this is our
     statement that their bill changes, and at the same weight it read as more of the workspace's
     own marketing blurb. Not an alarm colour either. It is a fact, not a warning. */
  color: var(--auth-text);
  line-height: 1.45;
}

/* Confirm / cancel summary: keyless dl rendered as a two-column grid. */
.subscribe-summary {
  margin: 0.25rem 0 0;
  padding: 1rem 1.25rem;
  background: var(--auth-bg);
  border-radius: var(--auth-radius-sm);
}

.subscribe-summary-list {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 1.25rem;
  row-gap: 0.55rem;
  margin: 0;
  font-size: 0.92rem;
}

.subscribe-summary-list dt {
  font-weight: 500;
  color: var(--auth-text-muted);
}

.subscribe-summary-list dd {
  margin: 0;
  color: var(--auth-text);
}

/* The Details row mirrors the plan description, so honor its line breaks here too. The
   other summary rows (plan names, price) stay single-line. */
.subscribe-summary-desc {
  white-space: pre-line;
}

/* Secondary row of the picker's selection-driven action bar (Billing / Cancel plan):
   subscribe-actions.js shows these only when the selection is a held plan; without JS they
   render whenever the user holds anything. */
.subscribe-actions-secondary {
  display: flex;
  gap: 0.75rem;
  margin-top: 0.75rem;
}

.subscribe-actions-secondary .auth-btn {
  flex: 1;
  width: auto;
  height: 2.4rem;
  margin-top: 0;
  font-size: 0.88rem;
}

/* .auth-btn's explicit display beats the UA's [hidden] rule. Restate it so the JS's
   hidden toggling actually hides the buttons. */
.subscribe-actions-secondary .auth-btn[hidden] {
  display: none;
}

/* Held-but-not-offered plans (grandfathered, another app's product, an emptied catalog):
   compact self-service rows below the picker. */
.subscribe-other {
  margin-top: 1.5rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--auth-divider);
}

/* Wraps the row's buttons under its name once the name would get narrower than 10rem (two buttons on a phone). */
.subscribe-other-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.85rem;
  padding: 0.55rem 0;
}

.subscribe-other-row > form {
  margin-left: auto;
}

.subscribe-other-main {
  flex: 1 1 10rem;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.subscribe-other-name {
  font-weight: 600;
  color: var(--auth-text);
}

.subscribe-other-meta {
  font-size: 0.85rem;
  color: var(--auth-text-muted);
}

/* Inline-sized button for list rows (.auth-btn is full-width by default). */
.auth-btn--compact {
  width: auto;
  height: 2.25rem;
  margin-top: 0;
  padding: 0 0.9rem;
  font-size: 0.85rem;
}

/* Long-form legal pages (Privacy, Terms). Standalone documents that bypass the auth-shell
   centering: auth-shell-main vertically centers content, which pushes the top of a long
   page above the viewport. Legal pages set BareLayout=true and use this class instead. */
.legal-page {
  max-width: 44rem;
  margin: 3rem auto;
  padding: 0 1.5rem;
  color: var(--auth-text);
}

.legal-page h1 {
  font-size: 1.85rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  margin-bottom: 0.4rem;
}

.legal-page-effective {
  color: var(--auth-text-muted);
  font-size: 0.9rem;
  margin-bottom: 2.5rem;
}

.legal-page h2 {
  font-size: 1.15rem;
  font-weight: 600;
  margin-top: 2.25rem;
  margin-bottom: 0.6rem;
}

.legal-page p {
  line-height: 1.6;
  margin-bottom: 1rem;
}

.legal-page ul {
  padding-left: 1.4rem;
  line-height: 1.6;
  margin-bottom: 1rem;
}

.legal-page li {
  margin-bottom: 0.35rem;
}

.legal-page a {
  color: var(--auth-text);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.legal-page-foot {
  margin-top: 3rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--auth-divider);
  font-size: 0.88rem;
  color: var(--auth-text-muted);
}
