/* ============================================================================
   grabprompts — APP LAYER
   ============================================================================
   The signed-in surfaces: prompt-app, dashboard, login, locked page.

   Tokens only — every colour, size, radius and shadow comes from theme.css,
   which is linked first by partials/head.ejs. Nothing here hardcodes a hex;
   the "zero hex" test in scripts/test-public.js holds this line.

   Generic by design: no per-product styling exists or may be added. One
   renderer serves every product (§7), so a rule that only makes sense for one
   slug belongs in the config, not here.
   ========================================================================= */

[x-cloak] { display: none !important; }

/* ============================================================================
   APP SHELL
   ========================================================================= */

.app { width: 100%; max-width: var(--measure); margin: 0 auto; padding: var(--space-7) var(--space-5) var(--space-9); }
.app.narrow { max-width: var(--measure-xs); }

@media (max-width: 40rem) {
  /* Reclaim 16px of horizontal room on a phone — on a 360px screen that is 5%
     of the width, and this page is where a buyer actually works. */
  .app { padding: var(--space-5) var(--space-4) var(--space-7); }
}

.app-head { margin-bottom: var(--space-6); }
.app-head h1 { font-size: var(--text-3xl); margin-bottom: var(--space-3); }
.app-head .lede { max-width: var(--measure-sm); }

/* ============================================================================
   DASHBOARD — owned vs locked tiles
   ============================================================================
   The tile base lives in theme.css so the dashboard and the landing grid stay
   visually identical. Only the ownership state is expressed here. */

.tile-top { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); margin-bottom: var(--space-4); }
.tile-count { color: var(--text-subtle); font-size: var(--text-xs); }

/* Owned reads as "yours": accent edge and a tinted top rule. Locked stays a
   plain neutral card — dimming it would make a buyable product look broken. */
.tile.owned { border-color: var(--accent); box-shadow: var(--shadow-md); }
.tile.owned::before {
  content: ""; display: block;
  height: 3px; margin: calc(var(--space-5) * -1) calc(var(--space-5) * -1) var(--space-5);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
}

.pill-owned { background: var(--accent-soft); color: var(--accent-press); }
.pill-locked { background: var(--warning-soft); color: var(--warning); border-color: var(--warning-line); }

/* ============================================================================
   PROMPT-APP — the compact card grid
   ============================================================================
   THREE PER ROW on desktop, two at tablet, one on a phone.

   Each card is a scannable summary: angle name, a BLURRED preview and the copy
   actions. The preview is a deliberate excerpt (built in interpolate.js, not
   clipped by CSS) and is blurred for looks only — every copy button hands over
   a COMPLETE, unblurred, self-contained prompt regardless of what the face
   shows. The "Show full prompt" disclosure is gone; the full text now appears
   only as the manual-copy fallback when the clipboard fails. */

.results { margin-top: var(--space-8); }
.results-head {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-2);
  margin-bottom: var(--space-4);
  color: var(--text-muted); font-size: var(--text-sm);
}
.results-head strong { color: var(--text); }

/* WHAT TO DO WITH THE PROMPTS — `output.afterNote`, shown once results exist.
   Generic (§14.6): no per-product rule, just a note style any product can use
   by declaring the string. Tinted rather than bordered so it reads as guidance
   sitting with the results, not as a warning. --accent-soft is a flat token,
   not a color-mix, so there is no gradient fallback to guard here (§14.2). */
.results-note {
  margin: 0 0 var(--space-5);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--accent-soft);
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: 1.55;
}

.cards { display: grid; gap: var(--space-4); grid-template-columns: repeat(3, minmax(0, 1fr)); }

@media (max-width: 62rem) { .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 40rem) { .cards { grid-template-columns: 1fr; } }

.card {
  display: flex; flex-direction: column;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--transition), border-color var(--transition);
}
.card:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); }

.card-head { display: flex; gap: var(--space-3); align-items: flex-start; margin-bottom: var(--space-3); }

.num {
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 1.75rem; height: 1.75rem;
  border-radius: var(--radius-sm);
  background: var(--accent-soft); color: var(--accent-press);
  font-size: var(--text-xs); font-weight: var(--weight-bold);
}

.card h2 { font-size: var(--text-base); line-height: var(--leading-snug); }
.card .blurb { margin-top: var(--space-1); color: var(--text-subtle); font-size: var(--text-xs); line-height: var(--leading-snug); }

/* ---- the preview well ----
   Fixed height so a row of three cards lines up even when the angle names wrap
   differently, and BLURRED so the card face reads as "a prompt is ready" rather
   than as a wall of spec nobody is meant to read.

   THE BLUR IS COSMETIC, NOT SECURITY — say so wherever this is touched. The
   text is still in the DOM and plainly readable in view-source or devtools, it
   has to be, and the buyer owns it anyway. What protects the prompts is the
   ENTITLEMENT GATE: only an owner ever reaches this page. Nothing here may be
   described to a buyer as protection.

   It also never affects what is copied: copy() is handed the text from Alpine
   state, so the clipboard always gets the complete unblurred prompt. */
.preview-wrap {
  position: relative;
  flex: 1 1 auto;
  margin-bottom: var(--space-4);
}

.preview {
  height: 100%;
  padding: var(--space-3);
  min-height: 6.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-sunk);
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
  /* previewOf() already collapsed the whitespace to one paragraph, so this
     wraps normally — no pre-wrap, which would reintroduce the tall ragged
     block the compact grid exists to avoid. */
  overflow-wrap: break-word;
  overflow: hidden;

  filter: blur(3.5px);
  /* Unselectable and untabbable: a smear nobody can read should not be
     something a cursor or a keyboard can land in. */
  user-select: none;
  -webkit-user-select: none;
  pointer-events: none;
}

/* The affordance. Sits OUTSIDE the blurred element — a child would inherit the
   filter — and says what to do, since the text behind it cannot be read. */
.preview-hint {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3);
  border-radius: var(--radius-md);
  /* A soft veil so the hint reads cleanly over the texture underneath.
     Flat colour FIRST: where color-mix is unsupported the second declaration is
     dropped, and without the fallback the hint would sit unveiled on a blurred
     smear (§14 — same rule the gradients follow). */
  background: var(--surface);
  background: color-mix(in srgb, var(--surface) 62%, transparent);
  color: var(--accent-press);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  text-align: center;
  pointer-events: none;
}
.preview-hint .icon { color: var(--accent); flex: 0 0 auto; }

@media (prefers-reduced-transparency: reduce) {
  /* Some readers find a translucent veil over a busy texture harder, not
     easier. Make it opaque rather than clever. */
  .preview-hint { background: var(--surface); }
}

.card-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: auto; }
.card-actions .btn { flex: 1 1 auto; }

@media (max-width: 30rem) {
  /* Side by side these two are ~130px each — reachable, but a mis-tap copies
     nothing or opens a tab. Stacked they are unmissable. */
  .card-actions { flex-direction: column; }
  .card-actions .btn { width: 100%; }
  .panel .actions { flex-direction: column; }
  .panel .actions .btn { width: 100%; }
}

/* ---- full text, as the manual-copy escape hatch ----
   The "Show full prompt" disclosure is GONE. This block is revealed only when
   both clipboard paths have failed, because the failure notice tells the buyer
   to select the text by hand — a fallback pointing at nothing is worse than no
   fallback. It is not a browsing affordance and should not become one again. */
.card-full { margin-top: var(--space-4); border-top: 1px solid var(--border); padding-top: var(--space-3); }
.card-full-body { margin-top: var(--space-3); }

@media (pointer: coarse) {
  /* An inner scroll region on a touch screen swallows the page scroll: a thumb
     that lands on the prompt cannot get back out of it. Let the page scroll
     instead — the disclosure is already collapsed by default. */
  .prompt { max-height: none; overflow: visible; }
}

.block { margin-bottom: var(--space-4); }
.block:last-child { margin-bottom: 0; }
.block-label {
  margin-bottom: var(--space-2);
  color: var(--accent-press);
  font-size: var(--text-xs); font-weight: var(--weight-bold);
  letter-spacing: .08em; text-transform: uppercase;
}

.prompt {
  margin: 0 0 var(--space-2);
  padding: var(--space-3);
  max-height: 22rem;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-sunk);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: var(--leading-body);
  white-space: pre-wrap;
  word-break: break-word;
}

/* ============================================================================
   LOGIN
   ========================================================================= */

.login-head { text-align: center; margin-bottom: var(--space-6); }
.login-head .badge { align-self: center; }
.login-head h1 { font-size: var(--text-2xl); margin-bottom: var(--space-2); }
.login-head .lede { font-size: var(--text-base); }

.login-panel .actions .btn { width: 100%; }
.login-sent { margin-bottom: var(--space-5); color: var(--text-muted); font-size: var(--text-sm); }
.login-sent strong { color: var(--text); }

/* The code field is the one input that should feel like a code field. */
#code {
  font-family: var(--font-mono);
  font-size: var(--text-xl);
  letter-spacing: .32em;
  text-align: center;
}

.login-foot { margin-top: var(--space-5); text-align: center; color: var(--text-subtle); font-size: var(--text-sm); }

/* ============================================================================
   LOCKED PAGE
   ========================================================================= */

.locked-badge { background: var(--warning-soft); color: var(--warning); border-color: var(--warning-line); }

.lock-panel h2 { font-size: var(--text-xl); margin-bottom: var(--space-3); }
.lock-panel > p { margin-bottom: var(--space-4); color: var(--text-muted); }
.lock-panel .actions .btn { flex: 1 1 12rem; }

.price { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-5); font-size: var(--text-3xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); }
.price .muted { font-size: var(--text-sm); font-weight: var(--weight-normal); }

.lock-note { margin-top: var(--space-5); padding-top: var(--space-4); border-top: 1px solid var(--border); color: var(--text-subtle); font-size: var(--text-sm); }

/* ---- copy fallback notice ----
   Shown only when BOTH clipboard paths failed. It tells the buyer what to do
   instead rather than leaving a button that appears to do nothing. */
.copy-failed {
  margin-top: var(--space-2);
  color: var(--danger);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
}

/* ---- multi-frame copy buttons ----
   A three-frame layout needs each frame pasted into its own chat, so the
   buttons stack full-width and are numbered. Stacked rather than in a row:
   at three-per-row a card is ~272px of content, and "Copy 1st prompt" across
   three columns would be ~85px each — unreadable, and an unreadable button on
   the one control that decides whether the product works is not a trade worth
   making for a shorter card. */
.card-steps { display: grid; gap: var(--space-2); margin-top: auto; margin-bottom: var(--space-2); }
.card-steps .btn { width: 100%; }
.card-steps-label {
  color: var(--text-subtle);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
}

/* ── THE AGENCY-PANEL NUDGE + THE FIRST-RUN WELCOME ──────────────────────────
   A FRESH CLASS, CHECKED FIRST. `.panel-promo` already has two claimants
   (the bundle callout shares its declaration, and the dashboard's old agency
   card wore it) and `.panel-bar` is the reseller panel's own page header — this
   repo has been bitten three times by a second component borrowing a class that
   already had an owner (§23.10), so `.agency-bar` and `.start-here` were
   verified absent from BOTH stylesheets and every view before being used.

   IT IS A BAR, NOT A CARD, and the difference is the point: it sits ABOVE the
   pack grid rather than in it, full width, so it cannot be mistaken for a
   product tile and cannot be scrolled past.

   NO `.btn.primary` INSIDE IT. §19.5 keeps the owned card's solid accent Open
   button the only filled button on the page — that is what makes "yours" and
   "not yours" read at a glance — so the prominence comes from the BAR's tint
   and from a scoped button rule, never from a class the rest of the page counts.

   MOBILE-FIRST: one column stacked, the control full width and easy to hit;
   two columns only once there is room. No literal colour (§14.2). */
.agency-bar {
  display: grid;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
  padding: var(--space-5);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.agency-bar-main { min-width: 0; }
.agency-bar h2 { font-size: var(--text-xl); margin: 0 0 var(--space-2); }
.agency-bar p { margin: 0 0 var(--space-2); color: var(--text-muted); }
.agency-bar p:last-child { margin-bottom: 0; }
.agency-bar .eyebrow { margin-bottom: var(--space-1); }

/* THE LOUD VARIANT — a free trial, or a panel nobody has opened yet. Tinted
   and accent-bordered, with the one button on the bar filled. Flat colour
   BEFORE the gradient: where color-mix is unsupported the gradient is dropped
   and the bar would otherwise render transparent (§14's rule for every tinted
   band on this site). */
.agency-bar.agency-bar--loud {
  border-color: var(--accent);
  background-color: var(--accent-soft);
  background-image: var(--grad-tint);
}
/* SCOPED, so no new class is added to anything the page counts. */
.agency-bar.agency-bar--loud .btn {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--shadow-sm);
}
.agency-bar.agency-bar--loud .btn:hover {
  background: var(--accent-hover);
  box-shadow: var(--shadow-md);
}

/* INLINE ON THE PACK PAGE: after the work, quieter, and never tinted — this
   page is a tool and an upsell competing with the results is in the way. */
.agency-bar.agency-bar--inline {
  margin-top: var(--space-7);
  margin-bottom: 0;
  background: var(--surface-sunk);
}

.agency-bar-reframe { color: var(--text); font-weight: var(--weight-bold); }
.agency-bar-note, .agency-bar-quiet {
  font-size: var(--text-sm);
  color: var(--text-subtle);
}
.agency-bar-expiry { font-size: var(--text-sm); }
/* THE WARNING WINDOW. Amber, from the same ramp the panel's own expiry line
   uses, so "ending soon" looks the same wherever a buyer meets it. */
.agency-bar-expiry.is-soon { color: var(--warning); font-weight: var(--weight-bold); }
.agency-bar-go { margin: 0; }
/* FULL-WIDTH CONTROL ON A PHONE — a thumb aiming at a button that spans the
   bar cannot miss it. The 44px minimum comes from §18.2's coarse-pointer rule
   on `.btn`, never restated here. */
.agency-bar-go .btn,
.agency-bar-go .cta-form,
.agency-bar-go button { width: 100%; }
@media (min-width: 46rem) {
  .agency-bar { grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
  .agency-bar-go .btn,
  .agency-bar-go .cta-form,
  .agency-bar-go button { width: auto; }
}

/* ── THE FIRST-RUN WELCOME ───────────────────────────────────────────────────
   DELIBERATELY PLAINER THAN THE NUDGE ABOVE IT. Two tinted bars stacked would
   compete, and only one of them has revenue attached — this is orientation, so
   it reads as a note rather than an offer. */
.start-here {
  margin-bottom: var(--space-6);
  padding: var(--space-5);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.start-here h2 { font-size: var(--text-lg); margin: 0 0 var(--space-2); }
.start-here p { margin: 0 0 var(--space-3); color: var(--text-muted); }
.start-here .eyebrow { margin-bottom: var(--space-1); }
.start-here-steps {
  margin: 0 0 var(--space-3);
  padding-left: var(--space-5);
  color: var(--text);
  display: grid;
  gap: var(--space-1);
}
.start-here-note { font-size: var(--text-sm); color: var(--text-subtle); margin-bottom: 0; }
/* ON THE PACK PAGE it sits between the pack's own header and the inputs, so it
   needs no eyebrow and less weight — the heading above it already says which
   pack this is. */
.start-here.start-here--pack { margin-bottom: var(--space-5); }
.start-here.start-here--pack p:last-child { margin-bottom: 0; }

/* ── NOW PASTE IT — the step the product depends on ──────────────────────────
   Shown whenever there are prompts on screen, not only on a first run: this is
   the instruction for the thing in front of them rather than orientation about
   the product. Quiet, because it sits with the work. */
.results-paste {
  margin: 0 0 var(--space-4);
  color: var(--text);
  font-size: var(--text-sm);
  line-height: 1.55;
}
