/* ===================================================================== */
/* ONE DIALOG PATTERN — every modal in the app is the same object.        */
/* ===================================================================== */
/* All five dialogs (login · intro · payment · confirm · composer) render   */
/* through the single kit Dialog atom: ONE scrim + ONE panel, hard corners */
/* (--radius:0), no blur. The kit panel ships flat (1px border, no depth); */
/* here every PAPER dialog gets the brand's only depth cue — the hard ink  */
/* offset (--offset) over a 2px ink edge — so a modal reads as one object  */
/* lifted off the page, identically, never a flat floating rectangle.      */
/* The login is the dark variant of the same panel and deliberately opts   */
/* out of the paper offset below. Its complete treatment lives here.       */
.intro-card,
.payment-card,
.confirm-card,
.read-composer-card,
.purchase-card {
  border-width: 2px;
  box-shadow: var(--offset);
}

/* The form dialogs carry many fields, so the kit's 32rem panel reads cramped and
   tall on desktop. Widen them (the kit panel still caps height + scrolls; the
   panel's width:100% keeps them full-bleed on a phone). Login + intro stay narrow. */
.cl-dialog-panel.read-composer-card,
.cl-dialog-panel.payment-card,
.cl-dialog-panel.confirm-card {
  max-width: 44rem;
}

.cl-dialog-panel.purchase-card { max-width: 40rem; }

#intro-modal[data-intro-mode="offer"] .intro-card {
  max-width: min(72rem, calc(100vw - 32px));
}

/* ---------- Login ---------- */

/* The login fills the space between the (sticky 60px) app header and the
   footer, centered, without forcing the page past one viewport. */
/* Sign-in / sign-up renders through the single kit Dialog atom (.cl-dialog
   room=dark): one scrim + one panel. The overlay scaffolding (fixed/centering/
   scrim/panel chrome) now comes from the kit; the dark "threshold" look (fill,
   grain, inverted fields/buttons) comes from the brand-handoff block below.
   (.hidden — global display:none !important — handles the closed state.) */

/* The login is a DARK ROOM. The kit's .cl-dialog scrim is semi-transparent
   (--scrim rgba(16,20,18,0.62)); with only paper behind it the threshold
   composites to a dead mid-gray. Lay a real --screen ground on the login view so
   the scrim darkens an already-dark page and the room reads as a deliberate
   threshold, not an unstyled backdrop. (Header + footer already invert here.) */
body[data-view="login"] { background: var(--screen); }

.app-boot-panel {
  background: var(--surface);
  border: 2px solid var(--border-strong);
  margin: 48px auto 80px;
  max-width: 560px;
  padding: 28px;
}

.app-boot-panel.hidden { display: none; }

.app-boot-panel h1 {
  font-family: var(--serif);
  font-size: var(--fs-h2);
  margin: 6px 0 10px;
}

.app-boot-panel p:not(.cl-eyebrow) {
  color: var(--muted);
  font-family: var(--serif);
  line-height: 1.5;
  margin: 0 0 18px;
}

.app-boot-panel[data-tone="error"] {
  border-left: 5px solid var(--red);
}

/* One clean column: heading, fields, button pair, divider, Google, foot line.
   The form itself is the kit's .cl-stack (column + gap); the shell only caps the
   column width on desktop. The shell ships neutral (no form) and only reveals a
   form once [data-login-ready] is set after /api/config resolves — fixes FOUC. */
.login-shell {
  text-align: left;
  width: min(380px, 100%);
}

/* Neutral until config resolves: a tiny skeleton placeholder reserves the
   column so nothing flashes and the layout does not jump. */
.login-shell:not([data-login-ready]) #login-form::before {
  background: var(--screen-hairline);
  content: "";
  display: block;
  height: 168px;
}

/* The login title uses the same serif heading role as every other dialog. */

/* The sign-in column, the email/password fields, and the button pair all render
   through the kit atoms (.cl-stack column + gap · .cl-field · .cl-btn[data-full]).
   The platform panel hides via the global .hidden, so no bespoke shells remain. */

/* "or" divider: a hairline rule with a centered mono token. */
.login-divider {
  align-items: center;
  color: var(--screen-dim);
  display: grid;
  font-family: var(--brand);
  font-size: var(--fs-slug);
  font-weight: var(--fw-bold);
  gap: 12px;
  grid-template-columns: 1fr auto 1fr;
  letter-spacing: 0.12em;
  margin: 2px 0;
  text-transform: uppercase;
}

.login-divider::before,
.login-divider::after {
  background: var(--screen-hairline);
  content: "";
  height: 1px;
}

/* The serif “G” is the only local addition to the shared button. */
.google-button::before {
  content: "G";
  color: var(--gold);
  font-family: var(--serif);
  font-size: var(--fs-body);
  font-weight: var(--fw-reg);
  margin-right: 10px;
}

/* Foot line: a quiet "Reset password" link (a .cl-btn[data-variant=ghost]) on
   the left, the subtle inline auth status on the right. .cl-split lays it out;
   keep only the wrap + reserved-height so the empty status line holds its row. */
.login-foot {
  flex-wrap: wrap;
  min-height: 1.4em;
}

/* Standard sign-up note: Terms/Privacy + the transactional-vs-marketing email posture. */
.login-legal {
  margin: 2px 0 0;
  line-height: 1.5;
}
.login-legal a {
  color: var(--gold);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* The reset link reads as an underlined link, not a ghost button outline. */
.login-link {
  color: var(--gold);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.login-link:hover {
  text-decoration-thickness: 2px;
}

.auth-status.error {
  color: var(--red);
  font-family: var(--brand);
  font-weight: var(--fw-bold);
  letter-spacing: 0.03em;
}

/* The shared hold notice is paper-toned; this complete dark-room composition
   uses its accessible on-screen error treatment instead. */
#login-error.cl-notice {
  background: var(--screen);
  border-color: var(--screen-hairline);
  border-left-color: var(--red-on-screen);
  color: var(--red-on-screen);
}

/* ---------- First-run intro modal (replaces the orientation page) ----------
   Chrome (scrim, panel, max-width, close X) now comes from the kit Dialog atom
   (.cl-dialog / .cl-dialog-panel / .cl-dialog-dismiss). Only the content-specific
   bits the kit has no atom for live here: the numbered steps + supporting detail. */

/* The panel already scrolls (kit max-height + overflow-y:auto), but on shorter /
   phone viewports the long step list pushes START off-screen with no signal it's
   reachable. Pin START to the panel bottom as a sticky footer so the primary
   action stays in view while the steps scroll behind it. The button's ink fill is
   opaque; a paper-band box-shadow seals the small gap above it (the panel's own
   --space-5 padding keeps the side gutters clear, so no horizontal bleed needed). */
.intro-card #intro-start {
  position: sticky;
  bottom: 0;
  box-shadow: 0 calc(-1 * var(--space-3)) 0 var(--surface);
}

.intro-steps {
  counter-reset: intro;
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
}

.intro-steps li {
  border-top: 1px solid var(--border);
  color: var(--body);
  counter-increment: intro;
  font-family: var(--serif);
  font-size: var(--fs-small);
  line-height: 1.55;
  padding: 16px 0 16px 30px;
  position: relative;
}

/* Step numerals are INK, not gold: gold text on paper violates the token law
   (--gold is reserved for dark rooms / focus). Ink also out-emphasizes the bold
   step titles it indexes instead of washing out to tan beside them. */
.intro-steps li::before {
  color: var(--ink);
  content: counter(intro);
  font-family: var(--brand);
  font-weight: var(--fw-bold);
  left: 0;
  position: absolute;
  top: 16px;
}

.intro-steps strong { color: var(--ink); }

.intro-legal-links {
  color: var(--ink);
  font-family: var(--brand);
  font-size: var(--fs-slug);
  margin: 0;
}

.intro-legal-links a,
.intro-privacy a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.intro-legal-links a:hover,
.intro-privacy a:hover {
  text-decoration-thickness: 2px;
}

.intro-privacy {
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-family: var(--brand);
  font-size: var(--fs-slug);
  line-height: 1.6;
  margin: 0 0 22px;
  padding-top: 16px;
}

/* ---------- Contextual zero-credit Project Pass offer (#305) ---------- */

.intro-card [tabindex="-1"]:focus { outline: 0; }

#intro-modal[data-intro-mode="offer"] .intro-card {
  max-width: min(50rem, calc(100vw - 32px));
}

.project-pass-modal {
  display: grid;
  gap: var(--space-5);
  margin: 0 auto;
  max-width: 42rem;
}

.project-pass-modal-head,
.project-pass-modal-explainer {
  display: grid;
  gap: var(--space-2);
}

.project-pass-modal-head > *,
.project-pass-modal-explainer > * { margin: 0; }
.project-pass-modal-title { font-size: clamp(2.25rem, 6vw, 4rem); }
.project-pass-modal-lede { color: var(--muted); max-width: 44ch; }

.project-pass-modal-explainer {
  border-top: 1px solid var(--border-strong);
  padding-top: var(--space-4);
}

.project-pass-modal-explainer .cl-heading { max-width: 28ch; }
.project-pass-modal-explainer .cl-text { max-width: 58ch; }

/* The offer's headline is a clamp() display face and the explainer runs to 58ch,
   so the content is taller than the panel at every common viewport — measured
   overflow 125px at 1440x900 up to 550px at 360x640. That pushed the only buy
   button to y=883..928 inside an 844px-tall phone: a writer arriving from an ad
   saw the price and no way to act on it. Pin the whole actions row to the panel
   bottom so the primary action, the sample, and the legal line stay in view
   while the explainer scrolls behind.

   This pins the ROW, not the button. Pinning .project-pass-modal-buy the way
   .intro-card #intro-start does above is a no-op here: the button fills its
   grid cell, so it has no travel inside its containing block and sticky never
   engages (measured — identical rects before and after).

   `bottom` is the negative of the panel's own padding so the row travels to the
   true panel edge, and the matching padding-bottom keeps the opaque band all the
   way down; without both, scrolled prose shows through beneath the legal line.
   The kit panel pads --space-5, which the offer-mode override drops to
   --space-4 under 480px, so both values are mirrored in the media query. */
.project-pass-modal-actions {
  align-items: center;
  background: var(--surface);
  border-top: 1px solid var(--border-strong);
  bottom: calc(-1 * var(--space-5));
  box-shadow: 0 calc(-1 * var(--space-3)) 0 var(--surface);
  display: grid;
  gap: var(--space-2);
  /* #311 stacks the sample under the primary, so the row is one column at every width. */
  grid-template-columns: 1fr;
  padding-bottom: var(--space-5);
  padding-top: var(--space-4);
  position: sticky;
}

.project-pass-modal-actions p { margin: 0; }
.project-pass-modal-buy { min-height: 44px; }

.project-pass-modal-legal {
  line-height: 1.55;
}
.project-pass-modal-legal a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

@media (max-width: 480px) {
  #intro-modal[data-intro-mode="offer"] .intro-card { padding: var(--space-4); }
  .project-pass-modal { gap: var(--space-4); }
  .project-pass-modal-actions {
    align-items: stretch;
    bottom: calc(-1 * var(--space-4));
    padding-bottom: var(--space-4);
  }
}

/* ---------- App footer (site nav from inside the workbench) ---------- */

.app-footer {
  border-top: 1px solid var(--border);
  margin-top: 64px;
  padding: 32px 24px 44px;
  text-align: center;
}

/* On the dark login threshold the footer is quiet legal copy, not a marketing
   nav. Keep it in normal flow: a fixed footer collided with the form/legal copy
   on short phone viewports and made zoomed layouts impossible to read. */
body[data-view="login"] .app-footer {
  background: transparent;
  border-top: 0;
  margin-top: 0;
  padding: 16px 24px 20px;
}
body[data-view="login"] .app-footer-fine { color: var(--screen-dim); }

.app-footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 20px;
  justify-content: center;
  margin: 14px 0 0;
}

.app-footer-links a {
  color: var(--faint);
  font-family: var(--brand);
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-decoration: none;
  text-transform: uppercase;
  transition: color 0.18s ease;
}

.app-footer-links a:hover { color: var(--ink); }

.app-footer-fine {
  color: var(--faint);
  font-family: var(--brand);
  font-size: var(--fs-slug);
  line-height: 1.6;
  margin: 0 auto;
  max-width: 64ch;
}

/* Dedicated sign-in surface. Dark-room component retuning lives here with the
   authentication flow instead of in a late brand override sheet. */
.login-view {
  align-items: center;
  background: var(--screen);
  color: var(--on-screen);
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: calc(100svh - 60px);
  padding: 48px 24px;
}

.login-view.hidden {
  display: none;
}

.login-room-card {
  background: var(--screen);
  border: 1px solid var(--gold-soft);
  box-shadow: 6px 6px 0 rgba(201, 168, 106, 0.5);
  color: var(--on-screen);
  padding: 36px 32px;
  position: relative;
}

.login-room-card::before {
  background-image: var(--grain);
  content: "";
  inset: 0;
  opacity: 0.055;
  pointer-events: none;
  position: absolute;
}

.login-room-card .login-title,
.login-room-card .cl-text {
  color: var(--on-screen);
}

.login-room-card .cl-label,
.login-room-card .cl-text[data-tone="muted"],
.login-room-card .cl-text[data-tone="faint"],
.login-room-card .auth-status {
  color: var(--screen-dim);
}

.login-room-card .cl-eyebrow,
.login-room-card .login-link {
  color: var(--gold-soft);
}

.login-room-card .cl-field-control {
  background: rgba(255, 255, 255, 0.06);
  border-color: var(--screen-hairline);
  color: var(--on-screen);
}

.login-room-card .cl-field-control::placeholder {
  color: var(--screen-dim);
}

.login-room-card .cl-field-control:focus-visible {
  outline-color: var(--gold-soft);
}

.login-room-card .cl-btn[data-variant="primary"] {
  background: var(--on-screen);
  border-color: var(--on-screen);
  color: var(--screen);
}

.login-room-card .cl-btn[data-variant="primary"]:hover {
  background: transparent;
  color: var(--on-screen);
}

.login-room-card .cl-btn[data-variant="secondary"],
.login-room-card .cl-btn[data-variant="ghost"] {
  background: transparent;
  border-color: var(--screen-hairline);
  color: var(--on-screen);
}

.login-room-card .cl-btn[data-variant="secondary"]:hover,
.login-room-card .cl-btn[data-variant="ghost"]:hover {
  background: rgba(255, 255, 255, 0.06);
}

.login-room-card .google-button::before,
.login-room-card .cl-btn.login-link {
  color: var(--gold-soft);
}

.login-room-card .login-divider {
  color: var(--screen-dim);
}

.login-room-card .login-divider::before,
.login-room-card .login-divider::after {
  background: var(--screen-hairline);
}

#login-plan-context {
  border-left: 2px solid var(--gold-soft);
  color: var(--on-screen);
  margin: var(--space-1) 0 0;
  padding-left: var(--space-2);
}

body[data-view="login"] :focus-visible {
  outline-color: var(--gold-soft);
}

body.intro-open,
body.payment-open,
body.confirm-open,
body.purchase-open {
  overflow: hidden;
}

.payment-element {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  margin: var(--space-1) 0;
  min-height: 116px;
  padding: var(--space-3);
}

.confirm-accept-button.confirm-danger {
  background: var(--red);
  border-color: var(--red);
  color: var(--surface);
}

.confirm-accept-button.confirm-danger:hover {
  filter: brightness(0.92);
}

@media (max-width: 480px) {
  .payment-actions,
  .confirm-actions {
    align-items: stretch;
    flex-direction: column-reverse;
  }

  .payment-pay-button,
  .payment-actions .cl-btn,
  .confirm-accept-button,
  .confirm-actions .cl-btn {
    text-align: center;
    width: 100%;
  }
}
