/* Base layout, form controls, and buttons. All values come from tokens.css
   (Principle III). When in doubt, add a token — do NOT hard-code. */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-sans);
  font-size: var(--font-size-base);
  line-height: var(--line-height-base);
  color: var(--color-ink);
  background: var(--color-surface);
}

a {
  color: var(--color-accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

a:hover {
  text-decoration-thickness: 2px;
}

:focus-visible {
  outline: 3px solid var(--color-focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

h1, h2, h3, h4 {
  font-weight: 600;
  line-height: var(--line-height-tight);
  margin-top: 0;
}

h1 { font-size: var(--font-size-xxl); }
h2 { font-size: var(--font-size-xl); }
h3 { font-size: var(--font-size-lg); }

.page-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* ── Masthead — sticky cream-glass surface with a gold hairline below.
   Replaces the original generic-navbar treatment with an editorial
   masthead: two-part wordmark (serif + Parisienne script), restrained
   nav links, and a primary CTA chip on the right. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  padding: var(--space-3) var(--space-5);
  background: rgba(252, 248, 238, 0.82);
  -webkit-backdrop-filter: blur(12px) saturate(1.05);
  backdrop-filter: blur(12px) saturate(1.05);
  border-bottom: 0;
}

/* Gold hairline rule — gradient transparent → gold → transparent.
   Sits as a pseudo-element so the sticky element doesn't get a
   harsh 1px line crossing the blur edge. */
.site-header::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: linear-gradient(to right, transparent, rgba(201, 163, 104, 0.55), transparent);
  pointer-events: none;
}

.site-header__inner {
  max-width: 1120px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
}

/* Two-part wordmark — "Event" Instrument Serif + "Cards" Parisienne
   with a multi-stop gold gradient text-fill. Echoes the hero headline
   and closing flourish on the landing page. */
.site-header__brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  color: var(--color-ink);
  line-height: 1;
  white-space: nowrap;
  transition: opacity var(--motion-quick) var(--motion-ease);
}

.site-header__brand:hover { opacity: 0.85; }

/* The logo glyph (admin upload or fallback envelope SVG). */
.site-header__brand-logo {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  color: var(--color-accent);
  display: inline-block;
  vertical-align: middle;
}

/* "Cardify" — script + gold gradient. Carries the brand's artistic
   weight; pair with .site-header__brand-plain ("Hub") for the wordmark. */
.site-header__brand-script {
  font-family: var(--font-script);
  font-weight: 400;
  font-size: 32px;
  /* line-height must include descender — Parisienne's 'y' tail otherwise
     sits below the line box, where background-clip: text has nothing to
     paint and the glyph renders transparent (= visually clipped). */
  line-height: 1.3;
  /* Use background-image (not the `background` shorthand) — iOS Safari has
     a long-standing bug where the shorthand + background-clip: text can
     fall through to the `color` fallback, rendering the wordmark in solid
     dark gold instead of the metallic gradient that Android Chrome shows. */
  background-image: linear-gradient(
    120deg,
    var(--gold-deep) 0%,
    #b08a4a 30%,
    var(--gold) 50%,
    #b08a4a 70%,
    var(--gold-deep) 100%
  );
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
          color: transparent;
  padding-right: 2px; /* keeps the script's swash from clipping */
}

/* Solid-color fallback only for engines that can't paint gradient text.
   Modern iOS/Android both support background-clip: text, so this branch
   only fires on very old browsers — the production look comes from the
   gradient block above. */
@supports not ((background-clip: text) or (-webkit-background-clip: text)) {
  .site-header__brand-script {
    color: var(--gold-deep);
  }
}

/* "Hub" — plain serif, smaller, baseline-aligned with the script. */
.site-header__brand-plain {
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 16px;
  letter-spacing: 0.02em;
  color: var(--color-ink);
  align-self: flex-end;
  margin-bottom: 4px;
}

/* ── Primary nav — text links with a hover swap to gold-deep, no
   permanent underline. Overrides the global a-rules inside .site-nav. */
.site-nav {
  display: flex;
  gap: var(--space-4);
  align-items: center;
}

.site-nav__link,
.site-nav a.site-nav__link {
  font-family: var(--font-serif);
  font-size: 16px;
  letter-spacing: 0.005em;
  color: var(--color-ink);
  text-decoration: none;
  padding: 4px 2px;
  border-radius: 2px;
  transition: color var(--motion-quick) var(--motion-ease);
}
.site-nav__link:hover,
.site-nav a.site-nav__link:hover {
  color: var(--gold-deep);
  text-decoration: none;
}
.site-nav__link:focus-visible,
.site-nav a.site-nav__link:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 3px;
}

/* "Quiet" nav links — for authenticated users where Templates/Pricing
   are secondary to Dashboard / New card. */
.site-nav__link--quiet {
  font-size: 15px;
  color: var(--color-ink-muted, var(--ink-3));
}

/* Inline sign-out form — strips form chrome so the sign-out button
   reads as a small ghost text link, visually subordinate to the
   primary "New card" CTA. */
.site-nav__signout {
  display: inline;
  margin: 0;
  padding: 0;
}
.site-nav__signout-btn {
  appearance: none;
  background: transparent;
  border: 0;
  padding: 4px 2px;
  cursor: pointer;
  font-family: var(--font-italic);
  font-style: italic;
  font-size: 14px;
  color: var(--ink-3);
  letter-spacing: 0.01em;
  transition: color var(--motion-quick) var(--motion-ease);
}
.site-nav__signout-btn:hover { color: var(--gold-deep); }
.site-nav__signout-btn:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ── Responsive masthead — collapse the secondary links on narrow
   viewports so the brand and the primary CTA always stay visible. */
@media (max-width: 720px) {
  .site-header__inner { gap: var(--space-3); }
  .site-nav { gap: var(--space-3); }
  .site-nav__link--quiet { display: none; }
  .site-header__brand-script { font-size: 26px; }
  .site-header__brand-plain  { font-size: 13px; }
  .site-header__brand-logo   { width: 26px; height: 26px; }
}

@media (max-width: 520px) {
  /* On phones, only the brand + primary CTA + (auth-only) sign-out remain.
     Secondary text links collapse out so the bar stays a single row. */
  .site-nav__link:not(.btn) { display: none; }
  .site-header { padding: var(--space-3) var(--space-4); }
}

main.page-main {
  flex: 1 0 auto;
  width: 100%;
  max-width: var(--layout-max);
  margin: 0 auto;
  padding: var(--space-7) var(--space-5);
  background: var(--color-accent-soft);
}

/* Override page-main's max-width centering: tinted background should
   span the full viewport width while content stays centered. */
.page-shell {
  background: var(--color-accent-soft);
}
.page-shell .site-header,
.page-shell .site-footer {
  background-clip: padding-box;
}

/* ── Auth card — pre-auth and landing surfaces wear this. ─────────
   Centered, elevated white card on tinted page background. */
.auth-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: 480px;
  margin: 0 auto;
  padding: var(--space-7);
  background: var(--color-surface-elevated);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}
/* Sign-in honeypot — off-screen, never shown to humans
   (design-docs/signin-abuse-hardening.md §4). */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.auth-card h1 {
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: var(--font-size-xxl);
  letter-spacing: -0.015em;
  margin: 0;
  line-height: var(--line-height-tight);
}
.auth-card > p {
  margin: 0;
  color: var(--color-ink-muted);
}
.auth-card form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0;
}
.auth-card .form-field {
  margin-bottom: 0;
}
.auth-card .banner {
  margin: 0;
}

@media (max-width: 480px) {
  .auth-card {
    padding: var(--space-5);
    border-radius: 0;
    max-width: 100%;
    box-shadow: none;
    border: 1px solid var(--color-border);
  }
}

/* "or" divider between the magic-link/password form and the Google
   button on /Account/SignIn. */
.auth-divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--color-ink-muted);
  font-size: var(--font-size-sm);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--color-border);
}

/* Continue-with-Google button. Uses .btn--secondary as the base. */
.auth-google-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  width: 100%;
}
.auth-google-glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4em;
  height: 1.4em;
  border-radius: 50%;
  background: #fff;
  color: #4285f4;
  font-weight: 700;
  font-family: var(--font-sans);
  font-size: 0.95em;
  border: 1px solid var(--color-border);
}

.site-footer {
  padding: var(--space-5);
  border-top: 1px solid var(--color-border);
  font-size: var(--font-size-sm);
  color: var(--color-ink-muted);
  text-align: center;
}

.site-footer__inner {
  max-width: var(--layout-max);
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  justify-content: center;
}

/* Base — shape and type only; no colour. A modifier MUST be added. */
.btn {
  appearance: none;
  border: 0;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  height: 36px;
  padding: 0 14px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition:
    transform 0.08s var(--motion-ease, ease-out),
    background 0.15s var(--motion-ease, ease-out),
    border-color 0.15s var(--motion-ease, ease-out),
    color 0.15s var(--motion-ease, ease-out),
    box-shadow 0.15s var(--motion-ease, ease-out);
}

/* Outline ghost — for forms / headers / standard contexts.
   Text colour is the warm-brown ink, not the gold accent: gold-on-white
   measures 2.35:1, well under WCAG AA (4.5:1). The brand expression is
   carried by the gold-tinted border + soft-gold hover background; the
   text itself stays readable. The `.card-edit__topbar-actions .btn--ghost`
   and `.topbar__refresh` overrides used to apply this fix locally — now
   that the base rule already passes contrast, those overrides are
   redundant but harmless. */
.btn--ghost {
  background: transparent;
  color: var(--color-ink);
  border: 1px solid var(--color-border);
}
.btn--ghost:hover {
  border-color: var(--color-accent);
  background: var(--color-accent-softer, var(--color-accent-soft));
}

/* Glassmorphic ghost — for buttons floating on tile art. */
.btn--ghost-overlay {
  background: rgba(255, 255, 255, 0.92);
  color: var(--color-ink);
  border: 1px solid rgba(255, 255, 255, 0.6);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.btn--ghost-overlay:hover {
  background: #ffffff;
}

/* Compact size — composable with any colour modifier. */
.btn--sm {
  height: 32px;
  padding: 0 12px;
  font-size: 12.5px;
}

/* Danger — destructive action signal. */
.btn--danger {
  background: var(--color-danger);
  color: #ffffff;
}
.btn--danger:hover { background: oklch(0.45 0.20 25); }
.btn--danger:active { transform: translateY(1px); }

/* Disabled — visually distinguishable from enabled.
   Covers <button disabled> and anchor-as-button (<a aria-disabled="true">). */
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: none;
}

/* Quiet text-link variant — used for in-page back-links and inline
   navigation. Sheds the pill geometry of `.btn` so the element reads
   as a link, not a control. Keeps the `.btn` class for layout
   compatibility (form-actions rows, etc.). */
.btn--link {
  background: transparent;
  border: 0;
  color: var(--color-accent);
  height: auto;
  padding: 0;
  border-radius: 0;
  font-weight: 500;
}
.btn--link:hover {
  text-decoration: underline;
}
.btn--link:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Action row at the foot of a form — primary + cancel/secondary pair.
   Wraps on narrow viewports so buttons keep their natural width. */
.form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-4);
  align-items: center;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
}

.form-field label {
  font-weight: 600;
}

.form-field input[type="text"],
.form-field input[type="email"],
.form-field input[type="password"],
.form-field input[type="date"],
.form-field input[type="datetime-local"],
.form-field input[type="number"],
.form-field input[type="search"],
.form-field input[type="file"],
.form-field select,
.form-field textarea {
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-elevated);
  color: var(--color-ink);
  font: inherit;
}

.form-field input:focus-visible,
.form-field select:focus-visible,
.form-field textarea:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 1px;
  border-color: var(--color-accent);
}

/* Reset the user-agent search clear button so it doesn't sit awkwardly
   against the new padded background. Webkit-only — Firefox renders no
   clear button by default. */
.form-field input[type="search"]::-webkit-search-cancel-button {
  cursor: pointer;
}

.form-field textarea {
  min-height: 96px;
  resize: vertical;
}

.field-hint {
  font-size: var(--font-size-sm);
  color: var(--color-ink-muted);
}

/* FR-017 — quiet help text rendered under a field's input. Small,
   secondary colour, never an alert. WCAG-AA contrast against
   --color-surface (--color-ink-muted #5e564f vs #fffaf4 ≈ 5.8:1). */
.field-description {
  font-size: var(--font-size-sm);
  color: var(--color-ink-muted);
  margin: 0;
}

.field-error {
  font-size: var(--font-size-sm);
  color: var(--color-danger);
}

/* FR-013 — required vs optional visual markers. The required *
   inherits the danger colour to read as "important", while the
   optional tag uses muted ink so the label still leads. Both are
   read by assistive tech via the `aria-required`/`aria-describedby`
   chain on the input, not via these visual cues alone. */
.required-marker {
  color: var(--color-danger);
  margin-left: var(--space-1);
}

.optional-marker {
  font-size: var(--font-size-sm);
  color: var(--color-ink-muted);
  font-weight: normal;
  margin-left: var(--space-2);
}

/* FR-025 + spec session-2 — single-choice (enum) field rendered as a
   fieldset+legend with one radio per option. Per-option description
   sits inline directly below its label, in the same quiet treatment
   as field-level descriptions. Always visible — no tooltip /
   disclosure gating. */
.form-field--enum {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0 0 var(--space-5);
  padding: 0;
  border: 0;
}

.form-field--enum legend {
  font-weight: 600;
  margin-bottom: var(--space-2);
  padding: 0;
}

.enum-option {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--space-3);
  row-gap: var(--space-1);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  align-items: start;
}

.enum-option input[type="radio"] {
  grid-column: 1;
  grid-row: 1 / span 2;
  margin: 0;
  align-self: center;
}

.enum-option__label {
  grid-column: 2;
  grid-row: 1;
  font-weight: 500;
}

.enum-option__description {
  grid-column: 2;
  grid-row: 2;
  font-size: var(--font-size-sm);
  color: var(--color-ink-muted);
}

.enum-option:has(input[type="radio"]:checked) {
  border-color: var(--color-accent);
  background: var(--color-accent-soft);
}

.banner {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-5);
}

.banner--error {
  background: var(--color-danger-soft);
  color: var(--color-danger);
  border: 1px solid var(--color-danger);
}
.banner__list {
  margin: var(--space-2) 0 0;
  padding-left: var(--space-5);
  list-style: disc;
  font-size: var(--font-size-sm);
  color: var(--color-ink);
}
.banner__list a {
  color: var(--color-danger);
  text-decoration: underline;
}

.banner--info {
  background: var(--color-accent-soft);
  color: var(--color-ink);
  border: 1px solid var(--color-border);
}

.banner--warning {
  background: var(--color-warning-soft);
  color: var(--color-ink);
  border: 1px solid var(--color-border);
}

/* The `data-state` attribute on <main> is the stable hook for the
   four-state-UX E2E test (T147b). Do not rename without updating it. */
main[data-state="loading"] .state-content--success,
main[data-state="loading"] .state-content--empty,
main[data-state="loading"] .state-content--error { display: none; }
main[data-state="empty"]   .state-content--success,
main[data-state="empty"]   .state-content--loading,
main[data-state="empty"]   .state-content--error { display: none; }
main[data-state="error"]   .state-content--success,
main[data-state="error"]   .state-content--loading,
main[data-state="error"]   .state-content--empty { display: none; }
main[data-state="success"] .state-content--loading,
main[data-state="success"] .state-content--empty,
main[data-state="success"] .state-content--error { display: none; }

/* Recipient shell (/c/{shareId}) uses no chrome — iframe fills viewport. */
body.card-shell-body { background: #000; }
body.card-shell-body .page-shell { min-height: 100vh; }
.card-shell {
  width: 100%;
  max-width: 100vw;
  margin: 0 auto;
  background: #000;
  aspect-ratio: 9 / 16;
  max-height: 100vh;
}

/* Free-tier referral badge on recipient view. Fixed-bottom so it floats
   over the iframe edge without altering .card-shell's aspect-ratio math. */
.card-attribution {
  position: fixed;
  left: 50%;
  bottom: 0.5rem;
  transform: translateX(-50%);
  padding: 0.35rem 0.9rem;
  font-family: var(--font-sans, system-ui, -apple-system, sans-serif);
  font-size: 0.8125rem;
  line-height: 1;
  color: rgba(255, 255, 255, 0.78);
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 999px;
  text-decoration: none;
  white-space: nowrap;
  z-index: 10;
  transition: color 120ms ease, background 120ms ease;
}
.card-attribution strong {
  font-weight: 600;
  color: #f5d68a; /* gold accent — matches site-header brand gradient */
  margin: 0 0.15em;
}
.card-attribution:hover,
.card-attribution:focus-visible {
  color: #fff;
  background: rgba(0, 0, 0, 0.75);
}

.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.card-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--space-4);
}

.card-list__item {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-elevated);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* Revoked cards stay visible for historical context but are desaturated
   and semi-transparent so they read as inactive at a glance. The copy
   link / edit-note buttons still work; the shared link itself 404s to
   the "no longer available" shell, which is the authoritative guard. */
.card-list__item--revoked {
  opacity: 0.55;
  filter: grayscale(1);
  background: var(--color-surface);
}
.card-list__item--revoked input[type="url"] {
  text-decoration: line-through;
}

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-5);
  list-style: none;
  padding: 0;
  margin: 0;
}

.gallery > li { margin: 0; }

.gallery__tile {
  display: block;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface-elevated);
  padding: var(--space-5);
  text-align: center;
  text-decoration: none;
  color: var(--color-ink);
  transition: box-shadow var(--motion-standard) var(--motion-ease);
}

.gallery__tile:hover { box-shadow: var(--shadow-md); }

.gallery__tile img {
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-md);
}

/* ── Legal pages (Privacy / Terms) — feature 028 ───────────────────── */
/* Long-form readable typography for the public Privacy + Terms pages.
   Reuses existing tokens; adds no new colours or fonts. */
.legal-content {
  max-width: 720px;
  margin: var(--space-6) auto;
  padding: 0 var(--space-4);
  line-height: 1.6;
}
.legal-content h1 { margin-bottom: var(--space-3); }
.legal-content h2 {
  margin-top: var(--space-6);
  margin-bottom: var(--space-2);
  font-size: var(--font-size-lg);
}
.legal-content p,
.legal-content ul,
.legal-content ol,
.legal-content dl {
  margin-bottom: var(--space-4);
}
.legal-content table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--space-3) 0 var(--space-5);
}
.legal-content th,
.legal-content td {
  text-align: left;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--color-border);
  vertical-align: top;
}
.legal-content code {
  background: var(--color-surface-elevated);
  padding: 1px 4px;
  border-radius: 3px;
  font-size: 0.95em;
}
