/* `color: inherit` is used throughout (wordmark, dropdown items, avatar button, ...) to pick up
   whatever the page's base text color is — that only works if something actually sets one.
   Previously nothing did: text color was left entirely to each engine's own dark/light default
   for `color-scheme: light dark`, which isn't consistent everywhere (notably Safari/iOS can end
   up applying a light/white default text color while a container's own explicit `background:
   white` stays white, producing invisible white-on-white text — reported live on a real device,
   not reproducible in desktop Chromium's `prefers-color-scheme` emulation, which is why it slipped
   past this codebase's usual live-headless-Chrome verification). Setting an explicit color here
   removes the guesswork for every element that inherits it, not just the one that got reported. */
:root {
  color-scheme: light dark;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: #1a1a1a;
}

body {
  max-width: 640px;
  margin: 0 auto;
  padding: 1.5rem;
  line-height: 1.4;
}

/* Author CSS always beats the UA stylesheet's own `[hidden] { display: none }` rule, regardless
   of specificity — so any class that sets `display` (`.dropdown-item`'s `display: block`, `.btn`'s
   `display: inline-block`, etc.) silently overrides `hidden`. Confirmed live: tab-admin/
   logout-button rendered fully visible to a logged-out guest even with `.hidden = true` correctly
   set, because `.dropdown-item { display: block }` won. This one rule keeps `hidden` authoritative
   everywhere, current and future uses alike, instead of patching each affected class one at a time. */
[hidden] {
  display: none !important;
}

header {
  margin-bottom: 1.5rem;
  position: relative;
}

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

.subtitle {
  color: #666;
  margin-top: 0.6rem;
}

.topbar {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}

.wordmark {
  font-weight: 700;
  font-size: 1.15rem;
  letter-spacing: -0.01em;
  margin-right: auto;
  color: inherit;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.brand-mark {
  flex: 0 0 auto;
  border-radius: 5px;
}

.account-menu {
  position: relative;
}

.avatar-button {
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 50%;
  border: 1px solid #888;
  background: transparent;
  color: inherit;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  font-size: 0.8rem;
  font-weight: 700;
}

.avatar-button:hover,
.avatar-button[aria-expanded="true"] {
  border-color: #2563eb;
  color: #2563eb;
}

.dropdown {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  min-width: 12rem;
  max-width: calc(100vw - 2rem);
  background: white;
  border: 1px solid #ccc;
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  padding: 0.4rem;
  z-index: 10;
}

.dropdown-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.55rem 0.6rem;
  border: none;
  background: transparent;
  color: inherit;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.9rem;
  box-sizing: border-box;
}

.dropdown-item:hover {
  background: rgba(37, 99, 235, 0.1);
}

.dropdown-item.active {
  color: #2563eb;
  font-weight: 600;
}

.dropdown-divider {
  height: 1px;
  background: #e5e5e5;
  margin: 0.4rem 0.2rem;
}

.dropdown-lang {
  padding: 0.2rem 0.6rem 0.3rem;
}

.dropdown-lang label {
  display: block;
  font-size: 0.75rem;
  color: #666;
  margin: 0 0 0.25rem;
}

.dropdown-lang select {
  width: 100%;
  padding: 0.4rem;
  border: 1px solid #ccc;
  border-radius: 6px;
  background: transparent;
  box-sizing: border-box;
}

/* The avatar icon relies on `currentColor`/`color: inherit`, which happens to auto-invert to a
   light color in Chromium via `color-scheme: light dark` (:root) — not guaranteed on every
   engine (notably older Safari/iOS), so both the button and the dropdown it opens get explicit
   dark-mode colors here rather than depending on that implicit inheritance. Without this, the
   dropdown in particular rendered as a solid white box with barely-legible text against a dark
   page — confirmed via a real headless-Chrome screenshot in prefers-color-scheme: dark.
   This block must stay AFTER the base .dropdown-item/.dropdown-divider/.dropdown-lang rules
   above: at equal specificity the later source-order rule wins regardless of the media query,
   so placing this block earlier silently let the base (light) rules win even in dark mode —
   confirmed live (the "Language" label rendered at #666, ~2.8:1 contrast, against the dark
   dropdown background instead of the intended #9aa1b0). */
@media (prefers-color-scheme: dark) {
  :root {
    color: #e5e7eb;
  }

  .avatar-button {
    border-color: #6b7280;
    color: #e5e7eb;
  }

  .avatar-button:hover,
  .avatar-button[aria-expanded="true"] {
    border-color: #60a5fa;
    color: #60a5fa;
  }

  .dropdown {
    background: #1e2230;
    border-color: #3a3f4e;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.55);
  }

  .dropdown-item:hover {
    background: rgba(96, 165, 250, 0.18);
  }

  .dropdown-item.active {
    color: #60a5fa;
  }

  .dropdown-divider {
    background: #3a3f4e;
  }

  .dropdown-lang label {
    color: #9aa1b0;
  }

  .dropdown-lang select {
    border-color: #3a3f4e;
    color: #e5e7eb;
  }
}

fieldset {
  border: 1px solid #ccc;
  border-radius: 8px;
  margin-bottom: 1rem;
}

label {
  display: block;
  margin: 0.5rem 0;
  font-size: 0.9rem;
}

input {
  display: block;
  width: 100%;
  padding: 0.4rem;
  margin-top: 0.2rem;
  box-sizing: border-box;
}

button[type="submit"],
#btn-start-camera,
#btn-stop-camera {
  padding: 0.6rem 1.2rem;
  border-radius: 6px;
  border: none;
  background: #2563eb;
  color: white;
  cursor: pointer;
}

.error {
  color: #b91c1c;
  margin-top: 0.75rem;
}

.actions {
  display: flex;
  gap: 0.75rem;
  justify-content: center;
  margin-top: 1rem;
}

.actions a,
#scanned-vcf-download {
  padding: 0.5rem 1rem;
  border-radius: 6px;
  background: #16a34a;
  color: white;
  text-decoration: none;
}

.hint {
  color: #666;
  font-size: 0.85rem;
  margin-top: 1rem;
}

.link-button {
  display: block;
  margin-top: 0.4rem;
  padding: 0;
  border: none;
  background: none;
  color: #2563eb;
  font-size: 0.85rem;
  text-decoration: underline;
  cursor: pointer;
}

@media (prefers-color-scheme: dark) {
  .link-button {
    color: #60a5fa;
  }
}

.scan-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
  margin-bottom: 1rem;
}

.file-fallback {
  font-size: 0.85rem;
  color: #666;
}

#scan-video {
  width: 100%;
  max-width: 480px;
  border-radius: 8px;
  background: #000;
}

#scan-result {
  margin-top: 1.5rem;
  padding: 1rem;
  border: 1px solid #ddd;
  border-radius: 8px;
}

/* Scan lives on the profile page now (ProfileRoutes.scala), below the card's own contact info —
   this just gives it a visual break from that content above it. */
.scan-section {
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid #ddd;
}

.eyebrow {
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #666;
  margin: 0 0 0.6rem;
}

/* ---------- shared button variants (tier choice, payment stepper) ---------- */

.btn {
  display: inline-block;
  padding: 0.55rem 0.9rem;
  border-radius: 6px;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  box-sizing: border-box;
  text-align: center;
}

.btn-outline {
  border: 1.5px solid #2563eb;
  color: #2563eb;
  background: transparent;
}

.btn-outline:hover {
  background: rgba(37, 99, 235, 0.08);
}

.btn-solid {
  border: none;
  background: #16a34a;
  color: white;
}

.btn-solid:hover {
  filter: brightness(1.05);
}

.btn-ghost {
  border: 1px solid #888;
  background: transparent;
  color: inherit;
}

#no-street-button {
  margin: 0.5rem 0 0.3rem;
}

#geo-fields {
  margin-top: 0.3rem;
}

/* ---------- environmental/SEE benefit calculator (Impact.scala), shown after generation ---------- */

#impact-calculator {
  margin-top: 1.5rem;
  padding-top: 1.2rem;
  border-top: 1px dashed #ccc;
}

#impact-card-count {
  max-width: 10rem;
}

.impact-metrics {
  list-style: none;
  padding: 0;
  margin: 0.8rem 0 0;
  font-size: 0.9rem;
}

.impact-metrics li {
  padding: 0.3rem 0;
  border-top: 1px solid #eee;
}

.impact-metrics li:first-child {
  border-top: none;
}

@media (prefers-color-scheme: dark) {
  #impact-calculator {
    border-top-color: #3a3f4e;
  }

  .impact-metrics li {
    border-top-color: #3a3f4e;
  }
}

/* ---------- card result: QR (left) + tier info (right), shown after generation ---------- */

.card-result {
  margin-top: 1.5rem;
}

.card-result-row {
  display: flex;
  gap: 1.5rem;
  align-items: flex-start;
}

.card-result-qr {
  flex: 0 0 auto;
  width: 220px;
  text-align: center;
}

.card-result-qr img {
  width: 100%;
  border: 1px solid #ddd;
  border-radius: 8px;
}

.card-result .actions {
  flex-wrap: wrap;
}

.card-result-card {
  flex: 1 1 auto;
  min-width: 12rem;
  max-width: 260px;
}

.card-result-card .biz-card {
  width: 100%;
}

.biz-card-qr-corner {
  position: absolute;
  right: 0.6rem;
  bottom: 0.6rem;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 3px;
  background: white;
  padding: 2px;
  box-sizing: border-box;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}

@media (max-width: 560px) {
  .card-result-row {
    flex-direction: column;
    align-items: center;
  }

  .card-result-card {
    width: 100%;
    max-width: none;
  }
}

/* ---------- "Get a Verified Card" prompt (create form, after the free card exists) ---------- */

#upgrade-cta {
  margin-top: 1.5rem;
  padding-top: 1.2rem;
  border-top: 1px dashed #ccc;
}

.upgrade-controls {
  display: flex;
  align-items: flex-end;
  gap: 1.2rem;
  flex-wrap: wrap;
  margin-bottom: 0.8rem;
}

.upgrade-controls .paid-currency-label {
  margin: 0;
}

.upgrade-controls .tier-price {
  margin: 0;
}

.tier-price {
  font-size: 1.2rem;
  margin: 0.2rem 0 0.7rem;
}

.mono {
  font-variant-numeric: tabular-nums;
}

.paid-currency-label {
  display: block;
  font-size: 0.78rem;
  color: #666;
  margin: 0.3rem 0 0.8rem;
}

.paid-currency-label select {
  display: block;
  width: auto;
  margin-top: 0.25rem;
  padding: 0.35rem;
  border: 1px solid #ccc;
  border-radius: 6px;
  background: transparent;
}

/* ---------- payment stepper ---------- */

.stepper {
  margin-top: 1rem;
  padding: 1rem;
  border: 1px solid #ddd;
  border-radius: 8px;
}

.steps {
  display: flex;
  align-items: center;
}

.step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  flex: 1;
  text-align: center;
}

.step .dot {
  width: 1.8rem;
  height: 1.8rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.78rem;
  border: 1.5px solid #ccc;
  color: #888;
}

.step.done .dot {
  background: #16a34a;
  border-color: #16a34a;
  color: white;
}

.step.current .dot {
  border-color: #2563eb;
  color: #2563eb;
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.15);
}

.step .label {
  font-size: 0.78rem;
  color: #888;
}

.step.current .label {
  color: #111;
  font-weight: 600;
}

.connector {
  flex: 1;
  height: 1.5px;
  background: #ddd;
  margin-bottom: 1.6rem;
}

.connector.done {
  background: #16a34a;
}

.payment-panel-body {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px dashed #ddd;
}

.step-actions {
  display: flex;
  gap: 0.7rem;
  margin-top: 0.9rem;
}

.step-actions .btn {
  flex: 1;
}

/* ---------- landing preview (sample card + New Card tile, shown before the form) ---------- */

#landing-preview {
  margin-bottom: 1.5rem;
}

/* ---------- dashboard: card grid + branded card tiles ---------- */

/* F2 (UX audit, 2026-08-25): "+ New card" used to sit at the end of the card grid — easy to miss
   on a full dashboard (observed after 13 cards in testing) for a different reason than the empty
   landing page (F1): position, not styling. Pinned in the header instead, always visible
   regardless of how many cards exist below it. */
.my-cards-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}

.my-cards-header h2 {
  margin: 0;
}

.plus {
  font-size: 1rem;
  line-height: 1;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 1rem;
}

/* F1 (UX audit, 2026-08-25): was a dashed, ghost-styled tile that read as a placeholder or
   inactive element rather than the primary call to action it actually is — most test users
   reportedly couldn't find it. Now the same solid, filled treatment as "Create My Card"/"Log In"
   elsewhere in the product (this class is only used by the landing page's tile-sized CTA now;
   the dashboard's pinned header button uses .btn.btn-solid instead — see F2 above). */
.new-card-tile {
  aspect-ratio: 16 / 10;
  border-radius: 10px;
  border: none;
  background: #16a34a;
  color: white;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 600;
}

.new-card-tile:hover {
  filter: brightness(1.05);
}

.new-card-tile .plus {
  font-size: 1.4rem;
}

/* F3 (UX audit, 2026-08-25): the card body carries every visual "clickable" signal already
   (color, elevation) but had no click handler — this makes that affordance real. Scoped to
   [role="button"] so it only affects the dashboard's own tiles (Account.buildCardTile), not the
   landing sample card or the post-generation result preview, which also use .biz-card but aren't
   clickable. */
.biz-card[role="button"] {
  cursor: pointer;
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}

.biz-card[role="button"]:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
}

.biz-card[role="button"]:focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: 2px;
}

/* F6 (UX audit, 2026-08-25): five actions (View/Edit/Add logo/Add photo/Delete, plus Remove
   logo/photo once set) used to wrap unevenly with flex-wrap. A fixed 3-column grid keeps every
   row even regardless of how many buttons are actually present (4-7, depending on logo/photo
   state) instead of forcing an exact slot count that would break at 7. */
.card-tile-actions {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.4rem;
  margin-top: 0.5rem;
}

.card-tile-actions a,
.card-tile-actions button {
  font-size: 0.78rem;
  padding: 0.3rem 0.55rem;
  border-radius: 6px;
  border: 1px solid #888;
  background: transparent;
  cursor: pointer;
  text-align: center;
  text-decoration: none;
  color: inherit;
}

.card-tile-actions .action-delete {
  border-color: #b91c1c;
  color: #b91c1c;
}

.biz-card {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: 10px;
  padding: 0.8rem 0.9rem;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #f6f7fb;
  background: linear-gradient(155deg, #1b2340 0%, #2b3563 100%);
  overflow: hidden;
}

.biz-card.card-expired {
  opacity: 0.55;
}

/* Wraps the logo (if any) + name/org so the logo sits in normal flow beside the text instead of
   floating over it — see the comment on `.card-logo-badge` below for why that matters. */
.biz-card-identity {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
}

.biz-card .name {
  font-weight: 700;
  font-size: 0.95rem;
}

.biz-card .org {
  font-size: 0.72rem;
  color: rgba(246, 247, 251, 0.72);
  margin-top: 0.1rem;
}

.status-chip {
  align-self: flex-start;
  font-size: 0.62rem;
  letter-spacing: 0.02em;
  padding: 0.2rem 0.45rem;
  border-radius: 3px;
}

.status-chip.verified {
  background: #ca8a04;
  color: #241a04;
}

.status-chip.free {
  background: rgba(255, 255, 255, 0.16);
  color: #f6f7fb;
}

.status-chip.soon {
  background: #dc2626;
  color: white;
}

/* Top-left, in normal flow (inside `.biz-card-identity`, a row alongside the name/org block) —
   NOT absolutely positioned. An earlier version floated this over the identity block and hid the
   name behind an opaque (white-background) image whenever both were present (see
   bizcard_logo_badge_overlap_fix in project memory); laying it out in-flow instead means the text
   simply sits next to it and can never be covered, on the dashboard tiles and the landing page's
   showcase card alike. */
.card-logo-badge {
  flex: 0 0 auto;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 4px;
  background: white;
  padding: 2px;
  object-fit: contain;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}

/* F7 (UX audit, 2026-08-25): mirrors .card-logo-badge's in-flow, small-badge treatment, but
   circular/cover like the profile page's own .card-photo — a personal portrait reads as a photo
   when cropped to a circle, unlike a logo which needs to stay fully visible uncropped. */
.card-photo-badge {
  flex: 0 0 auto;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 50%;
  object-fit: cover;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}

/* ---------- profile page logo (server-rendered, ProfileRoutes.scala) ---------- */

.card-logo {
  max-width: 96px;
  max-height: 96px;
  object-fit: contain;
  margin-bottom: 0.5rem;
}

/* Circular and `cover` (fills the frame, crops if needed) rather than `.card-logo`'s square/
   `contain` — a personal portrait reads as a photo when cropped to a circle; a logo needs to
   stay fully visible uncropped, which is why the two use different fit/shape rules. */
.card-photo {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  object-fit: cover;
  margin-bottom: 0.5rem;
  display: block;
}

.admin-stats {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.3rem 1rem;
  font-size: 0.9rem;
}

.admin-stats dt {
  color: #666;
}

.admin-stats dd {
  margin: 0;
  font-weight: 600;
  text-align: right;
}

#admin-feedback-list {
  list-style: none;
  padding: 0;
  font-size: 0.9rem;
}

#admin-feedback-list li {
  padding: 0.4rem 0;
  border-bottom: 1px solid #ddd;
}

footer {
  margin-top: 2.5rem;
  padding-top: 1rem;
  border-top: 1px solid #ddd;
}

footer fieldset {
  font-size: 0.9rem;
}

#feedback-message {
  width: 100%;
  box-sizing: border-box;
  padding: 0.4rem;
  margin-top: 0.2rem;
  font-family: inherit;
}

#feedback-thanks {
  color: #16a34a;
  margin-left: 0.5rem;
}

/* Full-viewport interrupt for an existing account with no sponsor school on file
   (SponsorshipGate.scala) — sits above everything else on the page (.dropdown's z-index: 10 is
   the previous highest in this file). */
.gate-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.5);
}

.gate-panel {
  max-width: 420px;
  width: 100%;
  background: white;
  color: #1a1a1a;
  border-radius: 10px;
  padding: 1.5rem;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.3);
}

/* Must stay after .gate-panel above — see the dropdown dark-mode comment earlier in this file for
   why source order (not just the media query) decides which same-specificity rule wins. */
@media (prefers-color-scheme: dark) {
  .gate-panel {
    background: #1e2230;
    color: #e5e7eb;
  }
}

/* The "add a strategy" forms on the Public Benefit View tab — several short inputs in a row
   rather than the stacked <label> blocks most other forms in this file use, since none of these
   fields need a full-width label above them. */
.pbv-strategy-form {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 1.5rem;
}

.pbv-strategy-form input[type="text"] {
  flex: 1;
  min-width: 10rem;
}

.pbv-strategy-form input[type="number"] {
  width: 5rem;
}

#pbv-quadrant {
  width: 100%;
  max-width: 480px;
  height: auto;
}
