/*
 * Public author landing page (P1). Layout/typography only — the brand tokens
 * (--paper/--ink/--accent/--serif/--sans/etc.) come from application.css, which
 * is loaded alongside this file by the "public" layout. Everything below keys
 * off --accent, so a `.palette-*` preset class (defined in application.css) on
 * the body recolors the whole page; the public default is terracotta, applied
 * by the layout. Per-workspace palette choice is the editor's job (later slice).
 */

body.public-page {
  background-image:
    radial-gradient(1100px 560px at 82% -10%, color-mix(in srgb, var(--accent-hi) 14%, transparent), transparent 60%),
    radial-gradient(820px 480px at -6% 106%, color-mix(in srgb, var(--accent-deep) 10%, transparent), transparent 60%);
  background-attachment: fixed;
}

.page {
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  padding: clamp(24px, 6vw, 64px) clamp(20px, 5vw, 28px) 32px;
  display: flex;
  flex-direction: column;
  gap: clamp(38px, 6vw, 58px);
}

/* ---- hero: the author's headline + bio (rendered inside .page) ----

   P-6 REPAIR, 2026-08-24 (public-refresh-spec §10 OQ-1 RESOLVED — Greg's call,
   this slice). The selector below WAS `.landing > h1`, a child combinator, and
   it had never matched anything: the <h1> is a GRANDCHILD, wrapped in
   `header.author-id` since the P1 identity restoration. So from P1 until today
   every author's name silently rendered at the global
   `h1 { clamp(30px, 5vw, 46px) }` and the display size on the next line was
   dead text — the worst shape a CSS defect can take, because a rule that
   matches nothing looks exactly like a rule that is right.

   Descendant combinator, so it now does what it has always claimed to do.
   `.landing` contains exactly one <h1> (landing_pages/show.html.erb:92), so the
   broadening reaches nothing new. Spacing does NOT move: `.author-id > h1`
   further down is later in source at equal specificity and keeps
   `padding-top: 0`. Only font-size (30px -> 40px at a 390px viewport) and
   line-height change — and the enlarged type is already covered by the shipped
   phone guard, whose 560px `overflow-wrap` set uses `.landing h1`, a descendant
   selector that has always matched the name.

   Pinned twice, on purpose: at source level in
   test/assets/public_css_refresh_test.rb (the combinator cannot come back), and
   behaviourally in test/system/responsive_public_page_test.rb (the name's
   RENDERED size is 40px at 390px, not 30px). ---- */
.landing h1 {
  font-size: clamp(40px, 9vw, 62px);
  line-height: 1.0;
  margin: 0;
  padding-top: clamp(6px, 3vw, 20px);
}
.landing .bio { color: var(--ink); max-width: var(--measure); }
.landing .bio p { margin: 0 0 1rem; }
.landing .bio p:last-child { margin-bottom: 0; }

/* ---- signup capture ---- */
.signup, .capture {
  background: var(--paper-hi);
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: clamp(22px, 4vw, 32px);
  display: flex; flex-direction: column; gap: 14px;
  position: relative; overflow: hidden;
}
.signup::before, .capture::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 4px;
  background: linear-gradient(90deg, var(--accent), var(--accent-hi), var(--accent-deep));
  opacity: .9;
}
.signup h2, .capture h2 { font-size: clamp(24px, 4.4vw, 30px); margin: 6px 0 0; }
.signup form, .capture form { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 6px; }
.signup input[type=email], .capture input[type=email] { flex: 1 1 240px; min-width: 0; margin: 0; }
.signup .error { color: var(--error); font-size: 15px; margin: 0; }
.fineprint { font-size: 13px; color: var(--ink-soft); margin: 2px 0 0; }

/* ---- standalone public states: signup thanks, uniform 404 ---- */
.thanks, .not-found {
  text-align: center;
  padding-top: clamp(40px, 12vw, 96px);
}
.thanks h1, .not-found h1 { font-size: clamp(34px, 7vw, 52px); }
.thanks p, .not-found p { margin: 0 auto; color: var(--ink-soft); }
/* The one way out of a reader-flow leaf (signup thanks, email confirm) — these
   pages otherwise dead-end. Vertical rhythm comes from the .page flex gap, as
   everywhere else; this only carries the quiet-link treatment the book page's
   "More from …" link already uses (.book-more below). No new token. */
.back-link { font-size: 16px; }
.back-link a { font-weight: 500; }

/* ---- footer ---- */
.page footer {
  border-top: 1px solid var(--line);
  padding-top: 22px; margin-top: 6px;
  display: flex; justify-content: space-between; align-items: center; gap: 14px; flex-wrap: wrap;
  font-size: 13.5px; color: var(--ink-soft);
}
.page footer .made { font-family: var(--serif); font-style: italic; }
.page footer .made b { font-style: normal; font-weight: 500; color: var(--ink); }
.page footer .made .dot { color: var(--accent); }

/* ---- book fan-out page (P4 S2) ----
   Coverless-but-intentional: the title is the hero, so the article gets extra
   top breathing room and the store buttons carry the visual weight. Every color
   resolves through an existing --token; no hue is minted here. */
.book {
  padding-top: clamp(40px, 10vw, 88px);
}
.book-head > h1 {
  font-size: clamp(40px, 9vw, 62px);
  line-height: 1.02;
  margin: 0;
}
.book-subtitle {
  font-family: var(--serif);
  font-style: italic;
  color: var(--ink-soft);
  font-size: clamp(19px, 3.4vw, 24px);
  margin: 10px 0 0;
}
.book .bio { color: var(--ink); max-width: var(--measure); }
.book .bio p { margin: 0 0 1rem; }
.book .bio p:last-child { margin-bottom: 0; }

/* Store buttons: a stacked column of large, thumb-sized targets. Borrows the
   button token treatment (accent fill, radius, focus ring) at list scale. */
.buy-list { display: flex; flex-direction: column; gap: 12px; }
.buy-link {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 44px;
  padding: 15px 20px;
  font-family: var(--sans); font-size: 17px; font-weight: 600;
  color: var(--paper-hi); background: var(--accent);
  border: 1px solid var(--accent); border-radius: var(--radius);
  text-decoration: none;
  transition: background .18s, transform .06s;
}
.buy-link:hover { background: var(--accent-deep); color: var(--paper-hi); }
.buy-link:active { transform: translateY(1px); }
.buy-link-go { font-size: 20px; line-height: 1; opacity: .85; }

.book-more { margin: 0; font-size: 16px; }
.book-more a { font-weight: 500; }

/* the mark is quiet by default and only announces itself as a link on
   hover/focus (theming/branding slice, Issue B2, design spec §5.1) — it must
   never read as an ad. Colour stays --ink (inherited on hover already); the
   underline is a color-mix() tint of --ink-soft, not a new hue/token. */
.made-link { color: inherit; text-decoration: none; }
.made-link:hover, .made-link:focus-visible {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--ink-soft) 45%, transparent);
  text-underline-offset: 3px;
}
.made-link:hover .dot { color: var(--accent-deep); }

/* ---- P1 landing shelf (P4 S2) ---- */
.shelf { display: flex; flex-direction: column; gap: 14px; }
.shelf > h2 { font-size: clamp(22px, 4vw, 28px); margin: 0; }
.shelf-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.shelf-item { margin: 0; }
.shelf-link {
  display: flex; flex-direction: column; gap: 2px;
  padding: 14px 18px;
  background: var(--paper-hi); border: 1px solid var(--line); border-radius: var(--radius);
  text-decoration: none; color: var(--ink);
  transition: border-color .18s, background .18s;
}
.shelf-link:hover { border-color: var(--accent); color: var(--ink); }
.shelf-title { font-family: var(--serif); font-size: 20px; font-weight: 500; }
.shelf-subtitle { font-size: 14px; color: var(--ink-soft); }

.rise { animation: rise .7s cubic-bezier(.2, .7, .2, 1) both; }
.d1 { animation-delay: .05s; } .d2 { animation-delay: .12s; } .d3 { animation-delay: .20s; }
@keyframes rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

/* ---- book fan-out cover (P4 S3, spec §3.9) ---- */
.book-cover {
  display: block; margin: 0 auto clamp(20px, 4vw, 32px);
  max-width: 200px; width: 100%; height: auto;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  box-shadow: 0 6px 24px color-mix(in srgb, var(--ink) 12%, transparent);
}
.book.has-cover { padding-top: clamp(24px, 6vw, 48px); } /* trims coverless breathing room */

/* ---- shelf now a row: thumb + text column (P4 S3) ---- */
.shelf-link { flex-direction: row; align-items: center; gap: 14px; }
.shelf-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.shelf-thumb {
  flex: 0 0 auto; width: 56px; height: 84px; object-fit: cover;
  border-radius: 6px; border: 1px solid var(--line);
}

/* ---- author links (P1 links restoration) — a labeled "elsewhere" list.
   Lighter than the commerce .buy-link (accent-filled CTA) and simpler than the
   two-line .shelf-link book card: a single-line labeled row that borrows the
   .shelf-link bordered-card treatment so it sits calmly beside the shelf below
   it. Every color resolves through a token; no hue is minted. ---- */
.links { display: flex; flex-direction: column; gap: 14px; }
.links > h2 { font-size: clamp(22px, 4vw, 28px); margin: 0; }
.link-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.link-item { margin: 0; }
.author-link {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 44px;                 /* thumb-sized target, matches .buy-link */
  padding: 13px 18px;
  background: var(--paper-hi); border: 1px solid var(--line); border-radius: var(--radius);
  text-decoration: none; color: var(--ink);
  transition: border-color .18s, color .18s;
}
.author-link:hover { border-color: var(--accent); color: var(--accent-deep); }
.author-link-label { font-family: var(--sans); font-weight: 500; font-size: 16px; }
.author-link-go { font-size: 17px; line-height: 1; opacity: .7; }

/* ---- landing headshot (conservative slot, P4 S3) ---- */
.author-photo {
  display: block; width: clamp(96px, 22vw, 160px); height: auto;
  aspect-ratio: 1 / 1; object-fit: cover;
  border-radius: 999px; border: 1px solid var(--line);
  margin: 0 0 clamp(12px, 3vw, 20px);
}

/* ---- restored author identity block (P1 restoration, spec §5.2) ---- */
/* A stacked hero unit: avatar -> name -> tagline. The wrapper's gap owns all
   inter-element spacing, so the photo/monogram swap never reflows. */
.author-id { display: flex; flex-direction: column; gap: clamp(12px, 2.5vw, 18px); }
/* CORRECTED 2026-08-24 (P-6). This line used to read "name inherits
   `.landing > h1` display sizing", which had never been true — that combinator
   was dead (see the repair note at the top of this file). The name really does
   take its size from `.landing h1` now; this rule only zeroes the name's own
   spacing so the .author-id wrapper gap owns every interval in the identity
   block, exactly as it did before the repair. */
.author-id > h1 { margin: 0; padding-top: 0; }
/* the wrapper gap owns spacing; drop the photo's own margin here so photo and
   monogram states are spaced identically (spec §5.2 note). */
.author-id .author-photo { margin: 0; }

/* ---- author kicker (P1 restoration, spec §3.4) — the eyebrow above the name.
   Small uppercase SANS in the accent, deliberately unlike the serif-italic
   .tagline so the two supporting lines read as distinct things. Palette-reactive
   via --accent-deep; no hue minted. ---- */
.author-id .kicker {
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--accent-deep);
  margin: 0;
}

/* headline demoted to a tagline under the name (borrows the .book-subtitle idiom) */
.landing .tagline {
  font-family: var(--serif); font-style: italic; color: var(--ink-soft);
  font-size: clamp(19px, 3.4vw, 24px);
  margin: 0; max-width: var(--measure);
}

/* monogram fallback: same circle geometry as .author-photo, accent-tinted so a
   photo-less page looks chosen. The fill is a color-mix of tokens (no hue
   minted) and recolors per .palette-* preset. */
.author-monogram {
  display: flex; align-items: center; justify-content: center;
  width: clamp(96px, 22vw, 160px); aspect-ratio: 1 / 1;
  border-radius: 999px; border: 1px solid var(--line);
  background: color-mix(in srgb, var(--accent) 14%, var(--paper-hi));
  color: var(--accent-deep);
  font-family: var(--serif); font-weight: 500; line-height: 1;
  font-size: clamp(40px, 9vw, 64px);
  user-select: none;
}

/* ---- P0a progress meter — PLACEMENT VARIANTS ONLY (design spec §4.6).
   Scale and measure; nothing else. The shared .meter / .meter-track /
   .meter-fill / .meter-caption primitive (colour, geometry, caption
   typography) lives in application.css, which both layouts load — so the fill
   keys off --accent and recolors per .palette-* preset for free. No colour is
   declared here, no token is minted, and no raw hex appears anywhere in this
   block. The D19 stamp has NO age-conditional styling by design: there is
   deliberately no --warn, no "stale" class, and no threshold rule here. ---- */

/* Book page: sits inside .book-head under the title. Deliberately NOT full
   width — a 720px rule under a 62px display title reads as a page divider, not
   a status line. ~360px is roughly a short title's measure, which is what makes
   it read as attached to the title. */
.book-meter { margin-top: clamp(16px, 3vw, 22px); max-width: 360px; }

/* Shelf: the third line of .shelf-text, beside a 56x84 thumb. Thinner (5px) and
   much shorter (<=200px) so five stacked rows read as a calm set of status
   lines rather than five accent rules. min() so it never overflows a narrow
   row — no breakpoint needed. */
.shelf-meter { margin-top: 6px; max-width: min(200px, 100%); }
.shelf-meter .meter-track { height: 5px; }
.shelf-meter .meter-caption { margin-top: 5px; }

/* ===========================================================================
 * PUBLIC REFRESH (docs/design/public-refresh-spec.md §3.4, 2026-08-24).
 * The type register + the one plate. COMPOSITION ONLY, exactly like everything
 * above it: no --token declared, no palette/ground preset, no raw hex / rgb() /
 * hsl() / named colour, no @media block, no new breakpoint, and no new motion —
 * the budget is still the single .rise entrance (direction §6).
 * ========================================================================= */

/* ---- the optical-size register (direction §3.2) --------------------------
   Newsreader is variable on `opsz 6..72`, and as of this slice both public
   layouts load that axis from our own server rather than a third party's.

   `font-optical-sizing: auto` ties opsz to the USED font size, which is exactly
   "scaled". Naming opsz explicitly OVERRIDES that and asks the face for one
   specific drawing whatever size the heading lands at, which is exactly "set" —
   the display cut has tighter apertures and higher contrast, and a heading that
   was drawn for its size reads as front matter rather than as body copy someone
   turned up. That is the whole move, and it is one property on nine selectors.

   MEASURED on the shipped subset (headless Chrome, Issue A): the same 60px
   string is 550.06px at `opsz 6` and 482.73px at `opsz 72`. The axis survived
   subsetting, so these rules do visible work rather than silently nothing.

   font-variation-settings names ONLY `opsz`, deliberately. CSS Fonts 4 §6.1
   gives the low-level property priority over the axes it LISTS and no others,
   so `font-weight` keeps driving `wght` for every selector below. Adding "wght"
   here would freeze the whole set at one weight, including anything nested
   inside these headings — do not add it.

   `font-optical-sizing: auto` beside a named opsz is a no-op. It is kept anyway,
   for parity with `.share-name` (application.css), which ships the pair: the
   printable share card is the same device at full size, and one redundant
   declaration is cheaper than two specs that look different to the next reader.

   NOTE WHAT IS NOT HERE: no font-size. Size and cut stay separable — the author
   name's size lives in the repaired `.landing h1` rule at the top of this file
   (P-6, spec §10 OQ-1), the book title's in `.book-head > h1`, and the cut lives
   here. Keep them apart; it is what lets either be changed without the other. */
.author-id > h1,
.book-head > h1,
.thanks h1,
.not-found h1 {
  font-optical-sizing: auto;
  font-variation-settings: "opsz" 60;
  letter-spacing: -0.02em;   /* direction §3.3; tightens, so it can only REDUCE
                                measured width — no new overflow exposure */
  line-height: 1.02;
}

/* The TEXT cut, for serif set at reading size. This is the half that earns its
   keep on a phone: the 6..72 axis draws sturdier stems and more open counters at
   the low end, which is what keeps a 19-24px serif italic legible at arm's
   length in bad hall light. Section headings (h2) are deliberately absent —
   direction §3.2 leaves them at auto. */
.landing .tagline,
.book-subtitle,
.shelf-title,
.page footer .made {
  font-variation-settings: "opsz" 14;
}

/* ---- the imprint plate on the buy block (direction §4) -------------------
   THE ONE MARKED OBJECT on a book page: the thing that hands the reader what
   they came for. This is the .signup/.capture device (above) restated on the
   list itself — same --paper-hi ground, same 1px --line, same 18px radius, same
   4px rule built from the same three accent tokens at the same 90deg. So it
   recolours with the author's preset for free, mints nothing, and needs no
   markup change at all.

   WHY THE <nav> *IS* THE PLATE, rather than sitting inside one (spec §11). The
   obvious build is a wrapper div. It was rejected three times over: it would add
   markup to a view whose OG / canonical / JSON-LD blocks this pass wants
   provably untouched; it would break the `nav.buy-list` shape that
   test/controllers/pages/public/books_controller_test.rb:70-83 pins; and — the
   real reason — `.rise d3` is on the <nav>, so a wrapper would paint an empty
   plate and then let its buttons fade up inside it 0.7s later, which reads as a
   loading state on a page that has none. Making the list itself the plate keeps
   the entrance as one object arriving.

   The cost, stated so nobody has to discover it: .buy-list now carries TWO rules
   about 200 lines apart in this file. The flex column stays where it was; this
   is the object the column sits on. Do not merge them and do not restate
   `display` here — this pass declares display on nothing (spec §7.2).

   ONE PLATE PER PAGE. The store list is the book page's only permitted plate;
   the author page's is .signup, the marketing front door's is .capture. The
   repetition across surfaces is the entire mechanism by which a 4px line becomes
   a brand instead of a decoration — so if a second accent rule ever appears on
   any of the three, the device is dead. Count them in a browser before shipping.

   THE PADDING IS LOAD-BEARING — this is the spec §5 checklist note, kept where
   someone tempted to tighten it will read it. `overflow: hidden` is what clips
   the ::before gradient to the radius, and it clips everything else that leaves
   the box too. The global :focus-visible ring is 2px solid at 3px offset = 5px
   OUTSIDE a .buy-link (application.css), against a padding that floors at 20px
   (the clamp minimum, reached at a 390px viewport) and only grows from there.
   Take this padding below ~8px and the first and last button's focus ring gets
   clipped by the plate — an invisible keyboard regression on the one page that
   exists to be tapped. Pinned in test/assets/public_css_refresh_test.rb. ---- */
.buy-list {
  background: var(--paper-hi);
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: clamp(20px, 4vw, 28px);
  position: relative; overflow: hidden;
}
.buy-list::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 4px;
  background: linear-gradient(90deg, var(--accent), var(--accent-hi), var(--accent-deep));
  opacity: .9;
}

/* ===========================================================================
 * RESPONSIVE — the public plane (mobile pass, 2026-08-02).
 *
 * This file had ZERO media queries until this block, and the reader-facing
 * pages are the ones people reach from a QR code — i.e. always from a phone.
 *
 * THREE TIERS, and all three values already existed in the codebase before
 * this block: 820px (application.css auth shell), 560px (application.css
 * .tier-bar), 480px (marketing.css hero CTA). No new breakpoint is invented.
 *
 * NOT ONE DECLARATION BELOW SETS A CUSTOM PROPERTY. The .palette-* /
 * .ground-* presets on <body> stay the only source of colour at every width
 * (D13) — a breakpoint that redefines --accent is a theme that changes when
 * you rotate your phone. Geometry and type scale only.
 * ========================================================================= */

/* --- NARROW (<= 820px) --------------------------------------------------- */
@media (max-width: 820px) {
  /* design: a fixed background attachment on a scrolling body is a known
     iOS Safari repaint cost, and it visibly bands/jumps against the
     collapsing URL bar. The wash is decoration; the palette it is mixed from
     is not, and scrolling the gradient with the page loses nothing an author
     chose. Same declaration, same gradients, same tokens — only the
     attachment changes. */
  body.public-page { background-attachment: scroll; }
}

/* --- PHONE (<= 560px) ---------------------------------------------------- */
@media (max-width: 560px) {
  /* design: THE fix for the one true public-plane overflow. .book-head > h1
     is clamp(40px, 9vw, 62px) — at 390px the 40px FLOOR wins, and
     text-wrap: balance does not break words. One long-word title
     ("Featherstonehaugh") pushes the whole document sideways.
     break-word, not anywhere: a title should still prefer to break between
     words, and only hyphenate-less-split when a single word cannot fit.

     WIDENED past the spec sketch, by supervisor ruling (2026-08-02): .shelf-
     title and .author-link-label are added to this set. Both are finding
     P-1's exact defect class — an unbreakable author-supplied word — on the
     same Wave 1 reader-facing surface: a real author with a long single-word
     book title overflows their own landing page's shelf row and links list
     today, not just the book-head display heading. This is a deliberate,
     documented extension of §5.1, not scope creep — do not "correct" it back
     to the narrower selector list without re-reading this comment. */
  .book-head > h1,
  .landing h1,
  .thanks h1,
  .not-found h1,
  .shelf-title,
  .author-link-label { overflow-wrap: break-word; }

  /* design: `break-word` alone does not green `.author-link-label` — CSS Text 3
     deliberately excludes `break-word` from a box's intrinsic min-content size,
     so a `.author-link` flex item with the default `min-width: auto` stays
     floored at the whole unbreakable word and never gets narrow enough for the
     permitted break to fire (MEASURED: 501px content in a 501px box, still
     shoving its row past the viewport). `.shelf-title` needed no equivalent
     rule because its ancestor `.shelf-text` already declares `min-width: 0`
     (public.css:171) for the same reason; this gives `.author-link-label`, which
     is itself the flex item here, the identical release valve rather than
     switching the shared rule above to `overflow-wrap: anywhere` for every
     selector in the set. */
  .author-link-label { min-width: 0; }

  /* design: the same protection for author-supplied prose. The bio is
     simple_format'ed author text and can contain a pasted URL. */
  .landing .bio,
  .book .bio { overflow-wrap: break-word; }

  /* design: the preview bar is APP chrome sitting over a themed reader page
     (layouts/public.html.erb pins .palette-plum .ground-parchment on it).
     At 390px badge + message + back-link have ~350px between them and no
     wrap rule, so the message gets crushed to a sliver. Give the label its
     own full-width line and let the back link sit under it, and raise that
     link to a real target — it is the only way out of preview. */
  .preview-bar { flex-wrap: wrap; row-gap: 6px; padding: 8px 16px; }
  .preview-bar-label { flex: 1 1 100%; }
  .preview-bar .button-quiet { min-height: 44px; padding: 10px 16px; }
}

/* --- SMALL (<= 480px) ---------------------------------------------------- */
@media (max-width: 480px) {
  /* design: the signup box is the entire purpose of an author page. The form
     already wraps (public.css:53), so at 390px the reader gets a full-width
     email field and then a ~120px button hanging at the left — the smallest
     thing on the page is the one action on the page. Stretch it.
     This is marketing.css:53-55's rule, verbatim in shape, applied to the
     component that shape was borrowed FROM. */
  .signup input[type=submit],
  .capture input[type=submit] { width: 100%; }
}
