/* ============================================================================
   Purpose Research, shared site chrome.

   Everything here is used by more than one page: tokens, header, footer, the
   cover treatment, the catalogue grid, buttons. Page-specific rules live with
   their page. The generators paste this file in ahead of each page's own rules,
   so there is exactly one definition of the chrome.

   The cover rules in particular must not be duplicated. CLAUDE.md: the Gerowise
   titles render in the same .grid definition as the Purpose Research titles "so
   the two groups cannot drift to different sizes at any breakpoint". The same
   argument applies across pages, which is why this file exists.

   Palette, cover rules and copy policy are all documented in CLAUDE.md.
   ========================================================================== */

:root{
  /* Light only, by decision. Declared rather than left to default so scrollbars
     and form controls do not render dark against warm paper on a dark-mode OS. */
  color-scheme:light;
  --paper:#FAF8F4; --surface:#F2EEE7; --text:#1C1A17; --text-2:#4A463F; --muted:#736A5F;
  --heading:#1F2161; --link:#262878; --brand:#2E3192; --rule:#E2DCD2; --on-brand:#FFFFFF;
  /* Same hue as --heading, less chroma. Saturated colour reads far louder across a
     full-width band than in the thin strokes of a headline: #1F2161 is 52% saturation,
     which is right for text and hot for a field. --band is 30% at the same hue. */
  --band:#252845;
  /* Offset right as well as down, so the light reads as upper-left and the eye is
     carried toward the text that follows. Two layers: a tight contact shadow and a
     soft cast. Kept low-alpha so it does not compete with the covers themselves. */
  --cover-shadow:1px 2px 2px rgba(28,26,23,.10), 4px 6px 10px rgba(28,26,23,.15), 9px 14px 26px rgba(28,26,23,.09);
  --cover-shadow-hover:2px 3px 3px rgba(28,26,23,.13), 6px 9px 14px rgba(28,26,23,.19), 14px 20px 34px rgba(28,26,23,.12);
  --display:'Jost',system-ui,sans-serif;
  --book:'EB Garamond',Georgia,serif;
  --gut:clamp(20px,5vw,56px);
}
*{box-sizing:border-box}
body{margin:0; background:var(--paper); color:var(--text);
  font-family:var(--book); font-size:19px; line-height:1.6; -webkit-font-smoothing:antialiased}
img{max-width:100%}
/* Links in running text are underlined by default. Colour alone cannot carry
   them: --link against --text measures 1.37:1, and the --rule hairline used
   previously is 1.29:1 on paper, a value this palette files as decorative.
   text-underline-offset drops the rule clear of Garamond's descenders. Every
   chrome link below sets text-decoration:none explicitly, so this default only
   reaches prose. */
a{color:var(--link); text-decoration:underline; text-decoration-color:var(--brand);
  text-decoration-thickness:1px; text-underline-offset:.18em}
a:focus-visible,button:focus-visible{outline:2px solid var(--brand); outline-offset:3px}
/* Removes the 300ms double-tap delay some mobile browsers still apply. */
a,button{touch-action:manipulation}
/* The header is sticky at 88px, so anything jumped to would otherwise land
   underneath it, including the skip link's own target. */
[id]{scroll-margin-top:104px}
/* max() rather than a plain gutter: on a notched phone in landscape the inset can
   exceed the gutter, and this is a full-bleed layout. */
.wrap{max-width:1180px; margin:0 auto;
  padding-left:max(var(--gut), env(safe-area-inset-left));
  padding-right:max(var(--gut), env(safe-area-inset-right))}
.skip{position:absolute; left:-9999px}
.skip:focus{left:8px; top:8px; background:var(--brand); color:#fff; padding:10px 16px; z-index:20;
  font-family:var(--display); font-size:15px}

/* ---- header ---- */
/* Reversed on indigo, not on Ink: identity at the top, closure at the bottom. Uses
   --band rather than --heading, because the same value that is right for headline
   text is too saturated once it fills a full-width strip. */
.site-head{background:var(--band); position:sticky; top:0; z-index:10}
.head-in{display:flex; align-items:center; justify-content:space-between; gap:28px; height:88px}
.home-link{display:block; line-height:0; border-bottom:0}
.home-link:focus-visible{outline:2px solid #A9ABE4; outline-offset:4px}
.site-head img{height:56px; width:auto; display:block}
.site-nav ul{display:flex; gap:30px; list-style:none; margin:0; padding:0}
.site-nav a{font-family:var(--display); font-size:15.5px; color:var(--paper); text-decoration:none; padding:4px 0;
  border-bottom:2px solid transparent}
.site-nav a:hover,.site-nav a[aria-current]{color:#FFFFFF; border-bottom-color:#A9ABE4}
.site-nav a:focus-visible{outline:2px solid #A9ABE4; outline-offset:3px}

/* ---- buttons ---- */
.cta-row{display:flex; gap:14px; flex-wrap:wrap}

/* Buy buttons, two labelled rows. The label column is a fixed measure so the two
   rows' buttons start on the same line, which is what makes the pair read as one
   block rather than as four loose objects. It collapses above the buttons on a
   narrow screen rather than squeezing them. */
.buy{display:grid; grid-template-columns:max-content 1fr; gap:12px 16px;
  align-items:center; margin-top:28px}
.buy-fmt{font-family:var(--display); font-size:12.5px; letter-spacing:.11em;
  text-transform:uppercase; color:var(--muted)}
.buy-btns{display:flex; gap:12px; flex-wrap:wrap}

/* Out of print. Outlined buttons rather than filled: these are not the press's own
   shelves, and the weight should say so. No affiliate line goes with them, because
   there is no affiliate link here. */
.oop{margin-top:28px; padding:18px 20px; background:var(--surface);
  border:1px solid var(--rule); border-left:3px solid var(--muted)}
.oop-note{margin:0 0 14px; font-family:var(--display); font-size:15.5px;
  line-height:1.5; color:var(--text); max-width:52ch}
.oop .buy-btns .btn{font-size:15px; padding:10px 20px}
/* One column on a narrow screen: the label sits above its own buttons rather than
   stealing width from them. */
@media (max-width:520px){
  .buy{grid-template-columns:1fr; gap:8px}
  .buy-fmt+.buy-btns{margin-bottom:6px}
}
.btn{font-family:var(--display); font-size:16px; letter-spacing:.02em; padding:13px 26px; text-decoration:none;
  display:inline-block; border:1px solid var(--brand); transition:transform .12s ease, background-color .12s ease}
.btn:active{transform:translateY(0)}
/* Hover, rewritten 2026-08-23. Both states were too quiet to read as interactive:
   the filled button moved brand to link blue, two values chosen to look alike, and
   the outlined one filled with --surface, which is invisible wherever the button
   sits on a surface band. Now the fill darkens to the heading indigo, an existing
   palette value at 13.67:1 with white, and the outlined button inverts, which is the
   least ambiguous signal available without adding a colour. Both lift 1px, and
   :active puts them back down, so a click is felt as well as seen. */
.btn:hover{transform:translateY(-1px)}
.btn-primary{background:var(--brand); color:var(--on-brand)}
.btn-primary:hover{background:var(--heading)}
.btn-secondary{background:transparent; color:var(--link)}
.btn-secondary:hover{background:var(--brand); color:var(--on-brand)}
/* Keyboard users had no visible state at all. Offset so the ring reads against both
   the filled and the outlined button, which already carries a 1px brand border. */
.btn:focus-visible{outline:2px solid var(--brand); outline-offset:3px}
.inline-link{font-family:var(--display); font-size:16px; color:var(--link); text-decoration:none;
  border-bottom:1px solid var(--brand); padding-bottom:2px}
/* Padding absorbs the extra border width, so the hover does not shift the line. */
.inline-link:hover{color:var(--brand); border-bottom-width:2px; padding-bottom:1px}

/* ---- shared cover treatment ---- */
/* The box only reserves grid space and holds the shelf line. It is never painted,
   so covers whose trim is not 2:3 show no letterbox band. The hairline and shadow
   ride on the image, so each cover keeps its true proportions. */
.cover{aspect-ratio:2/3; display:flex; align-items:flex-end; justify-content:center}
.cover img{max-width:100%; max-height:100%; width:auto; height:auto; display:block;
  border:1px solid var(--rule); box-shadow:var(--cover-shadow)}
.cover.empty{background:var(--surface); border:1px solid var(--rule); align-items:center;
  flex-direction:column; justify-content:center; gap:6px; padding:16px; text-align:center}
.cover.empty span{font-family:var(--display); font-size:12.5px; letter-spacing:.08em; text-transform:uppercase; color:var(--muted)}

/* ---- bands and section heads ---- */
.band{padding:clamp(48px,7vw,86px) 0; border-top:1px solid var(--rule)}
.band-surface{background:var(--surface)}
.sec-head{margin:0 0 clamp(28px,4vw,44px); max-width:60ch}
/* The 60ch cap is sized for the paragraph, which is set at 19px, but the heading
   renders at up to 42px and hits it far sooner. `.wide` lifts the cap for the
   heading only; the paragraph keeps its own 56ch measure, so the reading line
   never gets longer than it should. */
.sec-head.wide{max-width:none}
/* A slightly longer measure on the wide sections so the intro paragraph breaks at
   its sentence end rather than mid-list. At 56ch the catalogue names broke after
   "and", stranding "Meredith Sprunger" onto line two alongside the next sentence. */
.sec-head.wide p{max-width:66ch}
.sec-head h2{font-family:var(--book); font-weight:400; font-size:clamp(28px,3.8vw,42px); line-height:1.16;
  color:var(--heading); margin:0 0 12px; letter-spacing:-0.01em; text-wrap:balance}
.sec-head p{font-size:19px; color:var(--text-2); margin:0; max-width:56ch}
.sec-head .imprint{font-family:var(--display); font-size:13px; letter-spacing:.09em; text-transform:uppercase;
  color:var(--muted); margin:14px 0 0}

/* ---- the catalogue grid ---- */
/* Three per row, settled 2026-08-14. Both publisher groups use this one definition
   so their covers cannot render at different sizes at any breakpoint. This is the
   Books page size, where a reader has come to look at covers; the homepage runs
   the contact sheet instead. */
.grid{display:grid; grid-template-columns:repeat(3,1fr); gap:clamp(24px,3vw,38px) clamp(18px,2.4vw,30px)}
.item{display:flex; flex-direction:column}
.item a.cover-link{display:block; text-decoration:none}
.item a.cover-link:hover .cover img{box-shadow:var(--cover-shadow-hover)}
.cover img{transition:box-shadow .18s ease}
@media (prefers-reduced-motion:reduce){.cover img{transition:none}}
.item h3{font-family:var(--book); font-weight:400; font-size:18.5px; line-height:1.24; color:var(--text);
  margin:13px 0 3px; letter-spacing:.002em; text-wrap:balance}
.item a.cover-link h3{color:var(--text)}
/* Author left, year hard right on the same line. Baseline alignment keeps the year
   beside the first line of names, so the four-name Wong credits wrap underneath it
   rather than pushing it down. The shared right edge gives the grid a second
   alignment, which stops the cards reading as ragged text blocks. */
.item .by{display:flex; justify-content:space-between; align-items:baseline; gap:10px;
  font-family:var(--display); font-size:12.5px; letter-spacing:.09em; text-transform:uppercase;
  color:var(--muted); margin:0}
.item .by .who{min-width:0}
.item .by .yr{flex:none; font-variant-numeric:tabular-nums; letter-spacing:.04em}
.item .ed{font-family:var(--display); font-size:12.5px; color:var(--muted); margin:5px 0 0; font-style:normal}

/* ---- the publisher, on the About page ---- */
/* Moved out of the homepage's own stylesheet 2026-08-22, when the bio
   became a page. Shared chrome now, so it sits here with the rest. */
.pub{display:grid; grid-template-columns:220px minmax(0,1fr); gap:clamp(26px,5vw,58px); align-items:start}
/* height:auto is load-bearing, added 2026-08-23. The img carries width="560"
   height="707" so the browser can reserve the right box before the data URI
   decodes, and those attributes apply as presentational hints. With width:100%
   overriding the first and nothing overriding the second, the portrait was drawn
   220px wide and 707px tall inside the 220px column of .pub — two and a half
   times too tall. .cover img has always had this; .portrait was missed. */
.portrait{width:100%; height:auto; border:1px solid var(--rule);
  box-shadow:var(--cover-shadow); display:block}
.pub h1{font-family:var(--book); font-weight:400; font-size:clamp(27px,3.6vw,38px); line-height:1.16;
  color:var(--heading); margin:0 0 6px}
.pub .cred{font-family:var(--display); font-size:14px; letter-spacing:.09em; text-transform:uppercase;
  color:var(--muted); margin:0 0 20px}
.pub p{color:var(--text-2); max-width:60ch}
.journals-label{font-family:var(--display); font-size:12.5px; letter-spacing:.09em;
  text-transform:uppercase; color:var(--muted); margin:26px 0 0}
.journals{display:flex; flex-wrap:wrap; gap:8px 10px; margin:22px 0 24px; padding:0; list-style:none}
.journals li{font-family:var(--display); font-size:13.5px; color:var(--text-2); border:1px solid var(--rule);
  background:var(--paper); padding:6px 12px}

/* ---- footer ---- */
.site-foot{background:var(--text); color:#C4C0B8; padding:clamp(40px,6vw,64px) 0 34px; margin-top:clamp(48px,7vw,86px)}
.foot-in{display:flex; justify-content:space-between; gap:36px; flex-wrap:wrap}
.site-foot img{height:42px; width:auto; display:block; margin-bottom:14px}
.foot-tag{font-family:var(--book); font-style:italic; font-size:18px; color:#9B978F; margin:0}
.foot-nav{display:flex; gap:clamp(30px,6vw,70px); flex-wrap:wrap}
.foot-nav h2{font-family:var(--display); font-size:12.5px; letter-spacing:.13em; text-transform:uppercase;
  color:#9B978F; margin:0 0 12px; font-weight:500}
.foot-nav ul{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:9px}
.foot-nav a{font-family:var(--display); font-size:15px; color:#ECEAE5; text-decoration:none}
.foot-nav a:hover{border-bottom:1px solid #8385D8}
/* --brand measures about 1.6:1 against the Ink footer, so the default ring is
   effectively invisible here. Same lifted indigo the header band uses, 7.96:1. */
.foot-nav a:focus-visible{outline:2px solid #A9ABE4; outline-offset:3px}
.foot-base{border-top:1px solid #302E36; margin-top:38px; padding-top:20px; display:flex; gap:20px;
  flex-wrap:wrap; justify-content:space-between}
.foot-base p{font-family:var(--display); font-size:13px; color:#9B978F; margin:0}

/* ---- draft markers ---- */
.draft{border:1px dashed var(--brand); background:rgba(46,49,146,.045); padding:3px 8px;
  font-family:var(--display); font-size:12px; letter-spacing:.09em; text-transform:uppercase; color:var(--brand);
  display:inline-block; margin-bottom:10px}

@media (max-width:620px){
  body{font-size:18px}
  /* Option B, settled 2026-08-16. The wordmark plus four labels has a min-content
     width of about 353px, which overflows a 320px screen and a 375px one too; it
     clears only around 400px. The monogram is near square, so 47px wide at this
     height, and with the tighter gaps the row needs 276px against the 280px a
     320px screen leaves after the gutters. */
  .head-in{height:74px; gap:20px}
  .site-head img{height:46px}
  .site-nav ul{gap:14px}
  .site-nav a{font-size:14px}
  .grid{grid-template-columns:repeat(2,1fr)}
  /* Header is 74px here, not 88px. */
  [id]{scroll-margin-top:90px}
}
@media (prefers-reduced-motion:reduce){*{transition:none !important; animation:none !important}}

/* ---- articles ---- */
/* A publications list is a reference table wearing prose clothes: the citation is
   the content, and the action link expresses which right is actually held. States
   are distinguished by weight rather than colour, so the page does not turn into a
   field of buttons. See content/seo-baseline.md. */
.sec .note{font-size:17px; color:var(--text-2); max-width:62ch; margin:14px 0 0}
.yr{margin:34px 0 0}
.yr h2{font-family:var(--display); font-size:13px; letter-spacing:.10em; text-transform:uppercase;
  color:var(--muted); margin:0 0 10px; padding-bottom:7px; border-bottom:1px solid var(--rule)}
ol.arts{list-style:none; margin:0; padding:0}
ol.arts>li{padding:14px 0; border-bottom:1px solid var(--rule)}
ol.arts>li:last-child{border-bottom:0}
.cite{margin:0; font-size:17.5px; line-height:1.5; color:var(--text); max-width:78ch}
.meta{margin:7px 0 0; display:flex; flex-wrap:wrap; align-items:baseline; gap:8px 18px;
  font-family:var(--display); font-size:13.5px}
.doi{color:var(--link); text-decoration:none; word-break:break-all}
.doi:hover{text-decoration:underline}
.cited{color:var(--muted)}
.act{text-decoration:none; letter-spacing:.03em; transition:color .12s ease}
/* inline-block so the arrow can move; it is the only part of the row that can
   suggest direction without adding weight to eighteen list items. */
.act::after{content:" \2192"; display:inline-block; transition:transform .12s ease}
.act-download,.act-here{color:var(--brand); font-weight:600}
.act-request,.act-publisher{color:var(--text-2)}
/* Underline alone was the whole hover, and on the grey rows it was easy to miss.
   The colour lift is what registers; the arrow confirms it. */
.act:hover{text-decoration:underline; color:var(--brand)}
.act:hover::after{transform:translateX(3px)}
.act:focus-visible{outline:2px solid var(--brand); outline-offset:3px; text-decoration:underline}

/* ---- blog index ---- */
/* Same shape as the articles list, so it reuses .yr and ol.arts: a year heading
   over a ruled list. What differs is that the title is the link rather than a
   citation, because on the blog the title is the whole of the claim. Every href
   leaves for the WordPress install and never for a page here. */
.post-title{margin:0; font-size:19.5px; line-height:1.38; max-width:70ch}
.post-title a{color:var(--link); text-decoration:none;
  border-bottom:1px solid var(--rule); padding-bottom:1px}
.post-title a:hover{color:var(--brand); border-bottom-color:var(--brand)}
.post-when{font-family:var(--display); font-size:12.5px; letter-spacing:.09em;
  text-transform:uppercase; color:var(--muted); margin:0 0 5px}
/* Only three posts carry one, and they are McLafferty's own lines. The rest run
   as title and date rather than as something written to fill the column. */
.post-teaser{margin:7px 0 0; font-size:17.5px; line-height:1.5; color:var(--text-2); max-width:62ch}

/* ---- contact ---- */
/* Form left, the three answers right. A reader who already knows what they want
   starts typing; a reader who does not reads the column beside it and then knows
   what to put in the Subject. Neither has to scroll past the other. */
.contact{display:grid; grid-template-columns:1.15fr 1fr; gap:clamp(34px,5vw,72px); align-items:start}
.contact h1{margin:0 0 12px}
.contact .lede{font-size:19px; color:var(--text-2); max-width:44ch; margin:0 0 clamp(26px,3.4vw,34px)}
.form{margin:0}
.form fieldset{border:0; margin:0; padding:0; min-width:0}
.form legend{font-family:var(--display); font-size:12.5px; letter-spacing:.13em;
  text-transform:uppercase; color:var(--muted); padding:0; margin:0 0 18px}
.fld{margin:0 0 20px}
.fld label{display:block; font-family:var(--display); font-size:13px; letter-spacing:.08em;
  text-transform:uppercase; color:var(--text-2); margin:0 0 7px}
/* The required marker is type, not a red asterisk: an asterisk carries no meaning
   to a reader who has not been told what it means, and colour alone carries none
   to a reader who cannot see it. */
.fld .req-mark{font-size:11px; letter-spacing:.09em; color:var(--muted); margin-left:9px}
.fld .hint{display:block; font-size:14.5px; color:var(--muted); margin:0 0 8px; max-width:46ch;
  font-family:var(--book); letter-spacing:0; text-transform:none}
.fld input,.fld textarea{width:100%; box-sizing:border-box; font:inherit; font-size:17px;
  color:var(--text); background:var(--surface); border:1px solid var(--rule);
  padding:12px 14px; border-radius:0}
.fld textarea{resize:vertical; line-height:1.5}
.fld input:focus-visible,.fld textarea:focus-visible{outline:2px solid var(--brand); outline-offset:2px}
.form .send{margin:26px 0 0}
.form .send .btn{cursor:pointer}
/* Off-canvas rather than display:none, because a bot reads the markup and a
   hidden field it can see is the point. */
.trap{position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden}

/* What the form says back. Unused by the static preview, which cannot post; the
   WordPress theme renders one of these above the form after a submission.

   THE ONE PLACE A THIRD COLOUR APPEARS. CLAUDE.md's rule is one brand colour plus
   warm neutrals, and the reason given is that site chrome must recede or the cover
   grid becomes noise — a form message on the contact page is nowhere near a cover.
   It is confined to a 3px rule: the message text stays --text in both states, so
   the difference between "sent" and "please check that address" is carried by the
   sentence and not by the colour. Nothing is lost if the red is dropped.
   #7E2A2A measures 8.06:1 on --surface, AAA. */
.notice{margin:0 0 26px; padding:14px 18px; background:var(--surface);
  border:1px solid var(--rule); border-left:3px solid var(--brand)}
.notice p{margin:0; font-family:var(--display); font-size:15.5px; line-height:1.5;
  color:var(--text)}
.notice-error{border-left-color:#7E2A2A}
.asks .ask{margin:0 0 clamp(28px,3.4vw,38px); padding:0 0 clamp(24px,3vw,30px);
  border-bottom:1px solid var(--rule)}
.asks .ask:last-child{margin-bottom:0; padding-bottom:0; border-bottom:0}
.asks h2{font-family:var(--display); font-size:13px; letter-spacing:.10em; text-transform:uppercase;
  color:var(--muted); margin:0 0 12px}
.asks p{font-size:17px; line-height:1.55; color:var(--text-2); max-width:56ch; margin:0 0 12px}
.asks p:last-child{margin-bottom:0}
@media (max-width:820px){
  .contact{grid-template-columns:1fr; gap:clamp(38px,6vw,52px)}
}
