/* zpl-pdf — account page
 *
 * Split out of app.css on 2026-09-14. app.css was 1699 lines and every page loaded all of it;
 * the pages now load base.css plus their own file. The rules are UNCHANGED — this was a cut,
 * not a rewrite, so every measurement and every comment explaining it moved intact.
 *
 * Signup card, key output and usage gauges. Only account/ uses these.
 */

/* ─────────────── account ─────────────── */

.account { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 18px; }
.card {
  background: var(--bg-white);
  border-radius: var(--r);
  padding: 36px 32px;
}
.card h3 { font-size: 24px; font-weight: 600; letter-spacing: -0.022em; margin: 0 0 8px; }
.card-lede { margin: 0 0 26px; font-size: 17px; color: var(--ink-dim); letter-spacing: -0.01em; }

.field-label {
  display: block;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-dim);
  margin-bottom: 8px;
  letter-spacing: -0.005em;
}
.card input[type="email"],
.card input[type="password"],
.card select {
  width: 100%;
  font-family: var(--sans);
  font-size: 17px;
  padding: 13px 15px;
  margin-bottom: 18px;
  background: var(--bg-tint);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
 /* Apple changes no fill, shadow or outline colour on input focus — the platform's own
    focus ring does the work. We keep the accessible outline from :focus-visible and stop there. */
.card input:focus, .card select:focus { border-color: var(--accent); background: #fff; }
.card input::placeholder { color: var(--ink-faint); }

.keyin { display: flex; gap: 8px; align-items: start; }
/* The input takes the slack, but the buttons must not be squeezed: without flex-shrink: 0 the
   input's min-width crushes them until only their vertical padding is left and the pills
   render as circles. */
.keyin input { flex: 1; min-width: 0; margin-bottom: 0; font-family: var(--mono); font-size: 14px; }
.keyin .btn { flex: 0 0 auto; white-space: nowrap; }

/* Hit region, not paint. A .btn-sm is 12px text in 5px of padding — about 24px tall, which is
   the size Apple's own small controls are and is deliberate (see ui-research/apple/measurements.md
   §3C.3: a call to action earns attention by being the only blue pill, not by being large).
   What Apple pairs with that small paint is a hit region of at least 44x44pt, which we did not
   have here.

   Scoped to these two rows on purpose. The nav's .btn-sm is already centred in a 44px-tall bar
   (.nav { height: var(--nav-h); align-items: center }), so its target clears the minimum without
   help; adding a taller pseudo-element there would overhang the bar for no gain. These inline
   form rows are the only place the target is genuinely ~24px.

   inset/translateY centres the region on the button, so it grows symmetrically and never shifts
   the row. pointer-events stays on the parent — the pseudo-element only extends the area. */
.keyin .btn, .keyout-row .btn { position: relative; }
.keyin .btn::after, .keyout-row .btn::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  height: 44px;
}

.form-status { margin: 14px 0 0; font-size: 14px; min-height: 1.2em; }
.form-status.err  { color: var(--danger); }
.form-status.ok   { color: #248A3D; }
.form-status.busy { color: var(--ink-faint); }

.keyout {
  margin-top: 24px;
  padding: 22px;
  background: #F0FAF2;
  border-radius: var(--r-sm);
}
.keyout-warn { margin: 0 0 14px; font-size: 14px; letter-spacing: -0.01em; }
.keyout-row { display: flex; gap: 8px; align-items: center; }
.keyout-row code {
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  white-space: nowrap;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 11px 13px;
  font-size: 12px;
}
.keyout-id { margin: 14px 0 0; font-size: 14px; color: var(--ink-dim); }
.keyout-id code { font-size: 12px; color: var(--ink-faint); }

.usage-tier { margin: 22px 0 18px; font-size: 17px; color: var(--ink-dim); letter-spacing: -0.01em; }
.usage-tier b { color: var(--ink); font-weight: 600; }
.gauges { display: flex; flex-direction: column; gap: 20px; margin-bottom: 22px; }
.gauge-head { display: flex; justify-content: space-between; gap: 12px; font-size: 14px; margin-bottom: 8px; }
.gauge-name { color: var(--ink-dim); letter-spacing: -0.01em; }
.gauge-val { font-family: var(--mono); font-size: 12px; font-variant-numeric: tabular-nums; }
.gauge-track { height: 8px; background: #E9E9EB; border-radius: 4px; overflow: hidden; }
.gauge-fill { height: 100%; background: var(--accent); border-radius: 4px; transition: width var(--dur) var(--ease); }
.gauge-fill.warn { background: var(--warn); }
.gauge-fill.stop { background: var(--danger); }

.upgrade-note {
  margin-top: 24px;
  padding: 16px 18px;
  background: #FFF8EC;
  border-radius: var(--r-sm);
  font-size: 14px;
  color: var(--ink-dim);
  letter-spacing: -0.01em;
}
.upgrade-note b { color: var(--ink); font-weight: 600; }


/* ═══════════════════════════════════════════════════════════════════════
 * Sign-in and the signed-in dashboard  (2026-09-17)
 *
 * Added when /account/ became a two-state page: sign in, or manage the account you signed
 * into. See docs/planning/oauth-signin-2026-09-17.md §6. Everything above this banner is the
 * original signup/usage styling and is still in use — the gauges, .card, .keyin and .keyout
 * rules are shared by both states.
 * ═══════════════════════════════════════════════════════════════════════ */

/* One centred card. 460px is the measured width at which "Continue with Google" sits on one
   line at 15px with the mark and the button's own padding, without the card growing wide
   enough to read as a panel. */
.signin-shell { max-width: 460px; margin: 0 auto; }
.account-shell { max-width: var(--maxw-wide); margin: 0 auto; }

/* ─────────────── provider buttons ───────────────
 *
 * Deliberately NOT .btn. Google and GitHub both publish brand requirements for their sign-in
 * buttons — Google requires its official mark on a light or white surface with unaltered
 * colours, GitHub requires the invertocat on #24292F — and the site's blue pill satisfies
 * neither. Restyling these to match the rest of the page is a trademark problem, not a
 * refinement, so they keep provider shape and only borrow the page's radius and easing.
 *
 * 44px tall: the platform minimum for a touch target, and the same height as the nav
 * (--nav-h). The .btn-sm rows elsewhere on this page need a pseudo-element to reach 44px;
 * these are 44px of real paint, because they are the primary action.
 */
.oauth-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  min-height: 44px;
  padding: 0 18px;
  margin-bottom: 10px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.01em;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
.oauth-btn:hover { text-decoration: none; }
.oauth-btn:active { transform: scale(.985); }
.oauth-mark { display: inline-flex; flex: 0 0 auto; }

.oauth-btn--google {
  background: #fff;
  color: #1F1F1F;      /* Google's specified text colour on a white surface, not our --ink */
  border-color: var(--line);
}
.oauth-btn--google:hover { background: #F7F8F8; border-color: var(--separator); }

.oauth-btn--github {
  background: #24292F;  /* GitHub's specified surface */
  color: #fff;
}
.oauth-btn--github:hover { background: #32383F; }

/* Shown when the backend reports the provider is not configured (503 oauth_not_configured).
   Dimmed and inert rather than hidden: a missing button looks like a site that never offered
   the option, which sends the visitor hunting for it. */
.oauth-btn.is-unavailable { opacity: .4; pointer-events: none; }

/* ─────────────── or ─────────────── */
.or-rule {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 22px 0 20px;
  color: var(--ink-faint);
  font-size: 13px;
}
.or-rule::before, .or-rule::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line-soft);
}

.signin-alt-h { font-size: 15px; font-weight: 500; margin: 0 0 10px; letter-spacing: -0.01em; }
.signin-foot { margin: 22px 0 0; font-size: 13px; color: var(--ink-dim); letter-spacing: -0.01em; }

/* ─────────────── identity bar ─────────────── */
.identity-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  background: var(--bg-white);
  border-radius: var(--r);
  padding: 20px 24px;
  margin-bottom: 18px;
}
.identity-who { display: flex; align-items: center; gap: 14px; min-width: 0; }
.identity-avatar {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  font-weight: 600;
  background-size: cover;
  background-position: center;
}
.identity-text { min-width: 0; }
.identity-name {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.015em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.identity-sub {
  margin: 2px 0 0;
  font-size: 13px;
  color: var(--ink-dim);
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.identity-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

.plan-chip {
  font-size: 12px;
  font-weight: 500;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  background: var(--accent-soft);
  color: var(--accent);
  white-space: nowrap;
}

/* ─────────────── notices ─────────────── */
/* Same shape as .upgrade-note above, which is the pattern this page already had for a
   non-blocking aside. Kept as its own class because it is set from JS on a condition. */
.notice {
  padding: 16px 18px;
  border-radius: var(--r-sm);
  font-size: 14px;
  color: var(--ink-dim);
  letter-spacing: -0.01em;
  margin-bottom: 18px;
}
.notice b { color: var(--ink); font-weight: 600; }
.notice--warn { background: #FFF8EC; }

/* ─────────────── key list ─────────────── */
.keylist { display: flex; flex-direction: column; }
.keyrow {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 0;
  border-top: 1px solid var(--line-soft);
}
.keyrow:last-child { border-bottom: 1px solid var(--line-soft); }
.keydot {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ok);
}
/* A revoked key stays listed, dimmed with a hollow dot. Someone investigating a leak needs to
   see that the key was revoked; a key that simply vanishes from the list leaves them unsure
   whether the revoke worked. Same reasoning as accounts.ListAPIKeys, which returns them. */
.keyrow.is-revoked { color: var(--ink-faint); }
.keyrow.is-revoked .keydot { background: transparent; box-shadow: inset 0 0 0 1.5px var(--separator); }
.keyrow-main { flex: 1; min-width: 0; }
.keyrow-id {
  display: block;
  font-family: var(--mono);
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.keyrow-meta { display: block; font-size: 12px; color: var(--ink-faint); margin-top: 3px; }
.keyrow .btn { flex: 0 0 auto; }
.keylist-empty { font-size: 14px; color: var(--ink-dim); padding: 13px 0 3px; }

.usage-reset { margin: 4px 0 18px; font-size: 13px; color: var(--ink-faint); }

/* ─────────────── sign-in methods ─────────────── */
.card--full { margin-top: 18px; }
.idlist { display: flex; flex-direction: column; }
.idrow {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 0;
  border-top: 1px solid var(--line-soft);
}
.idrow:last-child { border-bottom: 1px solid var(--line-soft); }
.idrow-mark { flex: 0 0 auto; display: inline-flex; width: 20px; justify-content: center; }
.idrow-main { flex: 1; min-width: 0; }
.idrow-name { display: block; font-size: 15px; letter-spacing: -0.01em; }
.idrow-meta { display: block; font-size: 12px; color: var(--ink-faint); margin-top: 3px; }
.idrow .btn, .idrow .oauth-btn { flex: 0 0 auto; }
/* Inside a row the provider button is an ordinary-sized control, not the page's primary
   action, so it drops to .btn-sm metrics while keeping provider colours. */
.idrow .oauth-btn { width: auto; min-height: 0; margin: 0; padding: 6px 14px; font-size: 12px; border-radius: var(--r-pill); }

/* ─────────────── new key dialog ─────────────── */
.keydialog {
  max-width: 460px;
  width: calc(100% - 40px);
  border: none;
  border-radius: var(--r);
  padding: 30px 28px;
  background: var(--bg-white);
  color: var(--ink);
}
.keydialog::backdrop { background: rgba(0, 0, 0, .4); }
.keydialog h3 { font-size: 21px; font-weight: 600; letter-spacing: -0.02em; margin: 0 0 10px; }
.keydialog .keyout-row { margin-top: 16px; }
.keydialog .btn-block { margin-top: 18px; }

/* ─────────────── loading skeleton ─────────────── */
.skeleton-bar { pointer-events: none; }
.sk-lines { flex: 1; min-width: 0; }
.sk {
  background: linear-gradient(90deg, #ECECEF 25%, #F4F4F6 37%, #ECECEF 63%);
  background-size: 400% 100%;
  border-radius: 6px;
  animation: sk-shimmer 1.4s var(--ease) infinite;
}
.sk-avatar { width: 40px; height: 40px; border-radius: 50%; flex: 0 0 auto; }
.sk-line { height: 13px; margin-bottom: 8px; }
.sk-line--sm { height: 11px; margin-bottom: 0; }
.sk-block { height: 132px; border-radius: var(--r-sm); margin-top: 20px; }
@keyframes sk-shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }
/* A shimmer is decoration, and a reduced-motion visitor still needs to see the placeholder —
   so the animation goes and the shape stays. */
@media (prefers-reduced-motion: reduce) { .sk { animation: none; } }

/* ─────────────── narrow screens ─────────────── */
@media (max-width: 560px) {
  .card { padding: 28px 22px; }
  .identity-bar { padding: 18px; }
  /* The actions wrap under the name rather than squeezing it: at this width the plan chip and
     two buttons cannot share a line with an email address without both being truncated. */
  .identity-actions { width: 100%; }
  .keyin { flex-wrap: wrap; }
  .keyin input { flex: 1 1 100%; margin-bottom: 8px; }
}
