/* ============================================================
   FOND BOOKS — ORGANIC / NATURAL DESIGN SYSTEM
   ============================================================ */

/* 1. DESIGN TOKENS
   ============================================================ */
:root {
  /* Organic Palette — earth-drawn, light, warm.
     ------------------------------------------------------------------
     Every value that carries TEXT is cut to clear WCAG AA (4.5:1) on all
     three grounds it can land on: --card (#F5F1EB), --bg (#EAE4D9) and
     --muted (#DDD7CC). That constraint is what set --secondary and
     --muted-fg below, and it is the reason there are now two terracottas
     rather than one. Before 2026-09-01 the palette was picked for mood and
     never checked as information: axe reported colour-contrast failures on
     12 of 12 pages, ~1,000 nodes, the worst being the Amazon buy button at
     2.92:1 on 1,743 pages and a footer in which not one link passed.
     If you add a colour here, run it against those three grounds first. */
  --bg:           #EAE4D9;   /* warm parchment */
  --fg:           #2C2C24;   /* deep loam */
  /* Warm bark brown, softer than near-black for Oswald. One step darker than
     #6B5D52 as of 2026-09-01: that was 4.43:1 on --muted, which is the ground
     of the Historical Context box, so any heading placed inside one would have
     failed. Nothing rendered there yet — this closes the hole rather than
     fixing a live defect, and the shift is imperceptible on the other two
     grounds (5.63 -> 5.90 on card). */
  --heading:      #685A4F;
  --primary:      #5D7052;   /* moss green — 4.78 on card, 4.87 behind --primary-fg */
  --primary-fg:   #F3F4F1;   /* pale mist */
  --primary-hover:#4E5F44;   /* was hardcoded at four call sites */
  --primary-dark: #44543C;   /* deep moss — for text on a tinted moss ground */

  /* TWO terracottas, and they are not interchangeable.
     --secondary is the TEXT colour: same hue (30°) as the old #C18C5D, cut
     dark enough to read (5.93 card / 5.27 bg / 4.66 muted, and 6.67 behind
     white as a button ground). --secondary-bg is the original light tan,
     kept for decorative GROUNDS only. Never set --secondary-bg on type. */
  --secondary:    #84501F;   /* burnt sienna — terracotta, text safe */
  --secondary-bg: #C18C5D;   /* light terracotta — grounds and rules only */

  --accent:       #E6DCCD;   /* sand */
  --muted:        #DDD7CC;   /* stone — slightly darker to match bg */
  --muted-fg:     #5B5B50;   /* dried grass — 6.11 on card, 4.80 on muted */
  --border:       #CEC8BE;   /* raw timber — step darker */
  --card:         #F5F1EB;   /* card lifts off the darker background */

  /* Footer ground. Deep enough that the pale type on it passes: at the old
     --primary (#5D7052) the footer's own text ran 2.44–3.78:1 and NOTHING
     in it passed, on every page of the site. */
  --footer-bg:    #3F4E37;

  /* Shadows — moss & clay tinted, never pure black */
  --shadow-card:  0 2px 12px -2px rgba(93, 112, 82, 0.10);
  --shadow-soft:  0 4px 20px -2px rgba(93, 112, 82, 0.14);
  --shadow-float: 0 10px 40px -8px rgba(193, 140, 93, 0.18);

  /* Type scale — 1.25 ratio. There were 37 distinct font sizes in this file
     with no relationship between them (0.94, 0.97 and 0.98rem all appeared
     as separate values). New rules take a step from here; existing one-offs
     are retired as each page is touched. */
  --t-2xs: 0.75rem;    /* 12px — micro labels, eyebrows */
  --t-xs:  0.875rem;   /* 14px — captions, meta */
  --t-sm:  1rem;       /* 16px — body floor, never below this for prose */
  --t-md:  1.125rem;   /* 18px — lead paragraphs */
  --t-lg:  1.375rem;   /* 22px — card titles */
  --t-xl:  1.75rem;    /* 28px — section headings */
  --t-2xl: 2.25rem;    /* 36px — page titles */
  --t-3xl: 3rem;       /* 48px — hero */

  /* Spacing — 4px base, single scale */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px; --s8: 72px;

  /* Radii */
  --r-sm: 8px; --r-md: 16px; --r-lg: 24px; --r-pill: 9999px;

  /* Minimum comfortable touch target. Below 768px every inline link in a
     list row or sidebar is padded to clear this; the book title links on
     the award lists measured 34x25px before, which is the primary target
     of the primary journey. */
  --tap: 44px;

  /* Transitions.
     An explicit property list, not `all`. `all` animates every animatable
     property including `outline`, which meant the global focus ring faded in
     over 300ms from the browser default it was replacing: for the first
     ~150ms after tabbing to the Amazon button the ring was still white on
     terracotta, i.e. invisible, on the one interaction that most needs to be
     instant. Measured — 3px white immediately after Tab, 2px ink 600ms later.

     An allowlist also excludes it by construction rather than by a special
     case, keeps layout properties off the compositor, and still covers every
     transition the site actually asks for: colour and background on links and
     buttons, border and shadow on cards, transform on hover lifts, and the
     padding nudge on footer links.

     Spelled out per property on purpose: in the `transition` shorthand a
     trailing duration binds only to the LAST item in the list, so
     `transition: color, background-color 0.3s ease` gives colour a 0s
     duration and animates nothing but the background. */
  --transition: color 0.3s ease, background-color 0.3s ease, border-color 0.3s ease,
                box-shadow 0.3s ease, transform 0.3s ease, opacity 0.3s ease,
                padding 0.3s ease;
  --transition-slow: color 0.5s ease, background-color 0.5s ease, border-color 0.5s ease,
                     box-shadow 0.5s ease, transform 0.5s ease, opacity 0.5s ease;

  /* Legacy aliases — inline view styles pick these up automatically */
  --forest:       #5D7052;   /* was dark green → moss green */
  --parchment:    #DDD7CC;   /* was dark → stone */
  --sand:         #DDD7CC;   /* was gold-dim → muted stone */
  --slate:        #2C2C24;   /* was champagne → deep loam */
  --clay:         #5B5B50;   /* was pewter → dried grass; follows --muted-fg */
  --white:        #FFFFFF;
  --gold:         #84501F;   /* alias of --secondary: it is used as TEXT in
                                the homepage sidebar labels, so it has to be
                                the text-safe cut, not the light tan */
  --gold-dim:     rgba(222, 216, 207, 0.7);
  --gold-faint:   rgba(230, 220, 205, 0.4);
  --border-light: rgba(222, 216, 207, 0.5);
}

/* 2. RESET & BASE
   ============================================================ */
*, *::before, *::after { box-sizing: border-box }

html { scroll-behavior: smooth }

body {
  background-color: var(--bg);
  /* Subtle paper grain — SVG feTurbulence at low opacity */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.035'/%3E%3C/svg%3E");
  color: var(--fg);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 1rem;
  line-height: 1.75;
  margin: 0;
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

main#content { flex: 1 0 auto }

h1, h2, h3, h4 {
  font-family: 'Oswald', system-ui, sans-serif;
  color: var(--heading);
  line-height: 1.2;
  margin-top: 0;
  font-weight: 600;
}

a {
  color: inherit;
  text-decoration: none;
  transition: var(--transition);
}

p { margin-top: 0 }

strong { color: var(--fg); font-weight: 700 }

/* 2b. FOCUS
   ------------------------------------------------------------------
   One global ring. The site never suppressed focus outlines — Chrome's
   default was present on every control — but the default ring derives from
   the element's own colour, so on .btn-primary it resolved to #F3F4F1 and
   on .btn-gold to white: both invisible against parchment. This paints the
   ring in ink instead, so it reads on every ground the site has.

   :focus-visible, not :focus, so a mouse click on a button does not leave a
   ring behind it. The two components that forward a ring from an offscreen
   checkbox to its label (.search-icon, .summary-expand-toggle) keep their
   own rules further down; they cannot use this one because the element that
   takes focus is not the element that is seen.
   ============================================================ */
:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Pill shaped controls need the ring pushed clear of the radius, or it cuts
   the corners. */
.btn:focus-visible,
.subject-chip:focus-visible,
.decade-link:focus-visible,
.search-submit:focus-visible {
  outline-offset: 3px;
  border-radius: var(--r-pill);
}

/* 2c. TOUCH TARGETS
   ------------------------------------------------------------------
   Below 768px, an inline link inside a list row, a sidebar card or the
   footer is padded out to --tap. Measured before this: book title links on
   award lists 34x25px, year links 33x25, read alike links 22px tall,
   footer links 17-19px. Applied with flex centring rather than raw padding
   so the text stays optically where it was and only the hit area grows.
   ============================================================ */
@media (max-width: 767px) {
  .book-link,
  .year-col-link,
  .read-alike-link,
  .footer-link,
  .footer-bottom-link,
  .sidebar-title-link,
  .subject-card-link,
  .year-book-link,
  .year-award-link,
  .schedule-award-link {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
  }

  /* Nav and chips get their padding grown instead: they are already blocks
     and a min-height alone would leave the text top aligned. */
  .header-left .nav-link,
  .decade-link,
  .subject-chip {
    min-height: var(--tap);
    display: inline-flex;
    align-items: center;
  }
}

/* 3. UTILITIES
   ============================================================ */
.full-width   { width: 100%; display: block }
.flex-column  { display: flex; flex-direction: column }
.flex-gap     { display: flex; flex-direction: column; gap: 12px }
.no-bg        { background: transparent !important; border: none !important; box-shadow: none !important }
.no-underline { text-decoration: none !important; color: inherit }

@media (max-width: 767px) { .mobile-hide { display: none } }

/* 4. LAYOUT
   ============================================================ */
.wrapper {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  max-width: 1400px;
  padding: 0 16px;
  margin: 32px auto 16px;
  align-items: start;
}

/* Grid items default to min-width auto; without this, any fixed-width child
   (e.g. a 240px cover) widens the whole track past narrow viewports. */
.wrapper > * { min-width: 0 }

@media (min-width: 1024px) {
  .wrapper {
    grid-template-columns: 264px 1fr 330px;
    margin: 48px auto 32px;
    padding: 0 24px;
  }
  .wrapper.single-col {
    grid-template-columns: 1fr;
    max-width: 900px;
    display: block;
  }
}

/* 5. HEADER — floating frosted pill
   ============================================================ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 1000;
  padding: 10px 16px;
  background: transparent;
}

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 8px 0 16px;
  height: 60px;
  background: rgba(253, 252, 248, 0.88);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(222, 216, 207, 0.8);
  border-radius: 9999px;
  box-shadow: var(--shadow-soft);
}

.header-left,
.header-right {
  display: flex;
  align-items: center;
  gap: 2px;
}

.header-right { justify-content: flex-end }

/* Logo */
.logo-container { flex: 0 0 auto }

.logo-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
}

.logo-icon {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: var(--transition);
}

.logo-link:hover .logo-icon { background: var(--primary-hover) }

.logo-text {
  font-family: 'Oswald', system-ui, sans-serif;
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--fg);
  display: block;
}

.logo-sub { display: none }

.logo-link:hover .logo-text { color: var(--primary) }

/* Header nav */
.header-left .nav-link,
.header-right .nav-link {
  font-family: 'Nunito', sans-serif;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--muted-fg);
  padding: 6px 14px;
  border-radius: 9999px;
  transition: var(--transition);
}

.header-left .nav-link:hover,
.header-right .nav-link:hover {
  color: var(--primary);
  background: rgba(93, 112, 82, 0.09);
}

/* Result count and the note that a broad query is capped. Mobile first: both
   are small, quiet lines that sit under the heading and above the grid. */
.search-count {
  margin: 0.5rem 0 0;
  font-family: 'Nunito', sans-serif;
  font-size: 0.9rem;
  color: var(--muted-fg);
}

.search-more-note {
  margin: 1.25rem 0 0;
  padding: 0.85rem 1rem;
  font-family: 'Nunito', sans-serif;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--muted-fg);
  background: var(--accent);
  border: 1px solid var(--border);
  border-radius: 8px;
}

@media (min-width: 768px) {
  .search-count { font-size: 0.95rem }
  .search-more-note { font-size: 0.95rem }
}

/* 6. SEARCH
   ============================================================ */
.hidden-checkbox {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  appearance: none;
}

.search-container {
  display: flex;
  align-items: center;
}

.search-icon {
  cursor: pointer;
  font-family: 'Nunito', sans-serif;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--muted-fg);
  padding: 6px 14px;
  border-radius: 9999px;
  transition: var(--transition);
  user-select: none;
}

.search-icon:hover {
  color: var(--primary);
  background: rgba(93, 112, 82, 0.09);
}

/* `width: 0` hides the form to the eye but not to the keyboard: the input and
   the Go button stayed in the tab order, so tabbing through the header landed
   on an invisible field with no focus ring. `visibility` takes them out of it.
   It is delayed on the way closed so the width transition still plays, and
   immediate on the way open so the field can be focused straight away. */
.search-form {
  width: 0;
  overflow: hidden;
  visibility: hidden;
  transition: width 0.4s ease, visibility 0s linear 0.4s;
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

#search-toggle:checked ~ .search-form {
  width: 250px;
  visibility: visible;
  transition: width 0.4s ease, visibility 0s;
}

/* The checkbox that opens the form is offscreen, so forward its focus ring to
   the label standing in for it — the same thing .summary-expand-toggle does.
   Without this a keyboard user tabs onto a control with no visible focus. */
.hidden-checkbox:focus-visible ~ .search-icon {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: 4px;
}

.search-input {
  background: rgba(255, 255, 255, 0.85);
  border: 1px solid var(--border);
  color: var(--fg);
  padding: 7px 16px;
  width: 170px;
  border-radius: 9999px;
  font-family: 'Nunito', sans-serif;
  font-size: 0.85rem;
  transition: var(--transition);
}

.search-input::placeholder { color: var(--muted-fg) }

/* No `outline: none` here. A bare class and `:focus-visible` have the same
   specificity, so an `outline: none` further down the file silently beat the
   global focus ring and left the header's primary control with nothing but a
   1px border change to announce focus. The tint below is additional to the
   ring, not a replacement for it. */
.search-input:focus {
  border-color: rgba(93, 112, 82, 0.45);
  box-shadow: 0 0 0 3px rgba(93, 112, 82, 0.10);
}

.search-submit {
  background: var(--primary);
  border: none;
  color: var(--primary-fg);
  padding: 7px 16px;
  border-radius: 9999px;
  font-family: 'Nunito', sans-serif;
  font-size: 0.8rem;
  font-weight: 700;
  cursor: pointer;
  transition: var(--transition);
}

.search-submit:hover {
  background: var(--primary-hover);
  transform: scale(1.04);
}

/* 7. CARDS
   ============================================================ */
.main-card {
  background: var(--card);
  padding: 28px;
  border-radius: 24px;
  border: 1px solid rgba(222, 216, 207, 0.65);
  box-shadow: var(--shadow-card);
}

@media (min-width: 768px) { .main-card { padding: 40px } }

.sidebar-card {
  background: var(--card);
  padding: 20px;
  border-radius: 20px;
  border: 1px solid rgba(222, 216, 207, 0.65);
  box-shadow: var(--shadow-card);
  margin-bottom: 20px;
  transition: var(--transition-slow);
}

.sidebar-card:hover {
  box-shadow: var(--shadow-soft);
  transform: translateY(-2px);
}

aside { align-self: start }

/* 8. BUTTONS — pill shaped
   ============================================================ */
.btn {
  display: inline-block;
  padding: 10px 28px;
  font-family: 'Nunito', sans-serif;
  font-size: 0.9rem;
  font-weight: 700;
  cursor: pointer;
  border-radius: 9999px;
  border: 2px solid transparent;
  text-align: center;
  transition: var(--transition);
}

.btn-primary {
  background: var(--primary);
  color: var(--primary-fg);
  border-color: var(--primary);
  box-shadow: var(--shadow-soft);
}

.btn-primary:hover {
  background: var(--primary-hover);
  border-color: var(--primary-hover);
  transform: scale(1.04);
  box-shadow: 0 6px 24px -4px rgba(93, 112, 82, 0.3);
}

/* btn-gold → terracotta in organic theme */
.btn-gold {
  background: var(--secondary);
  color: #fff;
  border-color: var(--secondary);
  box-shadow: var(--shadow-float);
}

.btn-gold:hover {
  background: #a77347;
  border-color: #a77347;
  transform: scale(1.04);
  box-shadow: 0 8px 28px -6px rgba(193, 140, 93, 0.38);
}

/* Outlined rather than filled, for an action that is real but secondary. Used
   for the library link on book pages: it has to look as clickable as the two
   buy buttons above it, because a link nobody recognises as a link is no use to
   the borrower it exists for, while staying visually behind them so the primary
   paths still lead. `.btn` already reserves a 2px transparent border, so this
   sits on the same geometry with no shift. */
.btn-outline {
  background: transparent;
  color: var(--primary);
  border-color: var(--primary);
}

.btn-outline:hover,
.btn-outline:focus {
  background: var(--primary);
  color: var(--primary-fg);
  transform: scale(1.04);
}

.btn-small {
  font-size: 0.8rem;
  padding: 8px 20px;
}

.card-hover { transition: var(--transition-slow) }

.card-hover:hover {
  border-color: rgba(93, 112, 82, 0.28);
  transform: translateY(-4px);
  box-shadow: var(--shadow-float);
}

/* 9. TYPOGRAPHY COMPONENTS
   ============================================================ */
.section-divider {
  font-family: 'Oswald', system-ui, sans-serif;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--heading);
  border-bottom: 2px solid var(--muted);
  padding-bottom: 10px;
  margin-bottom: 16px;
  margin-top: 0;
}

.sidebar-title {
  font-family: 'Nunito', sans-serif;
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted-fg);
  border-bottom: 1px solid var(--border);
  padding-bottom: 8px;
  margin-bottom: 14px;
  margin-top: 0;
}

.affiliate-disclosure {
  font-family: 'Nunito', sans-serif;
  font-size: 0.7rem;
  line-height: 1.4;
  color: var(--muted-fg);
  margin: 12px 0 0;
}

.breadcrumb-nav,
.breadcrumbs {
  font-family: 'Nunito', sans-serif;
  font-size: 0.82rem;
  color: var(--muted-fg);
  margin-bottom: 16px;
}

.breadcrumb-nav a,
.breadcrumbs a {
  color: var(--muted-fg);
  transition: var(--transition);
}

.breadcrumb-nav a:hover,
.breadcrumbs a:hover { color: var(--primary) }

.breadcrumb-nav .sep,
.breadcrumbs .sep { margin: 0 6px; color: var(--border) }

.breadcrumb-nav .current { color: var(--fg); font-weight: 700 }

/* Badges */
.featured-label {
  display: inline-block;
  font-family: 'Nunito', sans-serif;
  font-size: 0.7rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  /* --primary-dark, not --primary: this sits on a moss tinted ground, which
     computes to #E6E4DC, and --primary against that is 4.22:1. */
  color: var(--primary-dark);
  background: rgba(93, 112, 82, 0.1);
  border-radius: 9999px;
  padding: 4px 14px;
  margin-bottom: 14px;
}

.featured-label.badge {
  display: inline-block;
  background: rgba(93, 112, 82, 0.1);
  color: var(--primary-dark);
  border-radius: 9999px;
  padding: 4px 14px;
  font-family: 'Nunito', sans-serif;
  font-size: 0.7rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  line-height: 1;
  border: none;
  box-shadow: none;
}

.label-container { margin-bottom: 20px }

/* Page headings */
.hero-title,
.page-title {
  font-family: 'Oswald', system-ui, sans-serif;
  font-size: 2.2rem;
  font-weight: 600;
  color: var(--heading);
  margin-bottom: 8px;
  margin-top: 0;
  line-height: 1.15;
}

@media (min-width: 768px) {
  .hero-title, .page-title { font-size: 2.8rem }
}

.hero-author {
  font-family: 'Nunito', sans-serif;
  font-size: 1rem;
  font-weight: 600;
  color: var(--muted-fg);
  margin-bottom: 28px;
}

.year-range-label {
  font-family: 'Nunito', sans-serif;
  font-size: 0.85rem;
  color: var(--muted-fg);
  margin: 4px 0 0;
}

.prize-intro {
  font-family: 'Nunito', sans-serif;
  font-size: 0.97rem;
  color: var(--fg);
  line-height: 1.8;
  margin: 1rem 0 1.5rem;
  max-width: 680px;
  border-left: 3px solid var(--secondary);
  padding-left: 18px;
  opacity: 0.88;
}

.page-header {
  margin-bottom: 24px;
  padding-bottom: 24px;
  border-bottom: 2px solid var(--muted);
}

/* 10. TABLE
   ============================================================ */
.modern-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 24px;
}

.modern-table th {
  padding: 12px 10px;
  text-align: left;
  border-bottom: 2px solid var(--muted);
  color: var(--muted-fg);
  text-transform: uppercase;
  font-family: 'Nunito', sans-serif;
  font-size: 0.65rem;
  letter-spacing: 0.1em;
  font-weight: 800;
}

.modern-table td {
  padding: 18px 10px;
  vertical-align: top;
  border-bottom: 1px solid var(--muted);
  color: var(--fg);
}

.modern-table tr:hover td {
  background: rgba(93, 112, 82, 0.04);
}

td.year-col {
  font-family: 'Oswald', system-ui, sans-serif;
  font-weight: 600;
  color: var(--secondary);
  width: 80px;
}

.title-col {
  font-family: 'Oswald', system-ui, sans-serif;
  font-size: 1.05rem;
}

.book-link {
  color: var(--heading);
  font-weight: 600;
  transition: var(--transition);
}

.book-link:hover { color: var(--secondary) }

.book-link-wrapper {
  display: block;
  color: inherit;
}

.author-name {
  display: block;
  font-family: 'Nunito', sans-serif;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--muted-fg);
  margin-top: 4px;
}

.context-col {
  font-family: 'Nunito', sans-serif;
  font-size: 0.875rem;
  color: var(--muted-fg);
  line-height: 1.65;
}

.no-award {
  color: var(--muted-fg);
  font-style: italic;
}

/* 10b. CROSS LIST LINK
   Sits under the table, where a reader who has run out of list needs somewhere
   to go. Quiet enough not to compete with the table, but the link itself is
   underlined and coloured: a link nobody recognises as a link earns no clicks.
   ============================================================ */
.list-crosslink {
  margin-top: 32px;
  padding-top: 20px;
  border-top: 2px solid var(--muted);
}

.list-crosslink p {
  font-family: 'Nunito', sans-serif;
  font-size: 0.94rem;
  line-height: 1.75;
  color: var(--fg);
  margin: 0;
  max-width: 680px;
  opacity: 0.88;
}

.list-crosslink-link {
  color: var(--primary);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 2px;
  /* Tap target on mobile: the link often wraps to its own line, and a bare
     inline run of text is a thin thing to hit with a thumb. */
  display: inline-block;
  padding: 2px 0;
}

.list-crosslink-link:hover,
.list-crosslink-link:focus {
  color: var(--secondary);
}

@media (min-width: 768px) {
  .list-crosslink {
    margin-top: 40px;
  }

  .list-crosslink p {
    font-size: 1rem;
  }
}

/* 11. DECADE NAVIGATION
   ============================================================ */
.decade-nav {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-bottom: 28px;
  padding: 10px 16px;
  background: rgba(253, 252, 248, 0.9);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(222, 216, 207, 0.8);
  border-radius: 16px;
  position: sticky;
  top: 88px;
  z-index: 10;
  box-shadow: var(--shadow-card);
}

.decade-label {
  font-family: 'Nunito', sans-serif;
  font-size: 0.65rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted-fg);
  white-space: nowrap;
  padding-top: 6px;
}

.decade-links {
  display: flex;
  gap: 2px;
  flex-wrap: wrap;
}

.decade-link {
  font-family: 'Nunito', sans-serif;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--muted-fg);
  padding: 4px 12px;
  border-radius: 9999px;
  border: none;
  background: transparent;
  transition: var(--transition);
}

.decade-link:hover {
  background: rgba(93, 112, 82, 0.1);
  color: var(--primary);
}

tr:target { background-color: rgba(93, 112, 82, 0.06) }

/* 12. BOOK COVERS
   ============================================================ */
.book-cover-gen {
  width: 100%;
  aspect-ratio: 2/3;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  padding: 14% 10% calc(14% + 24px);
  color: #fff;
  border-radius: 8px 12px 12px 8px;
  text-align: center;
  overflow: hidden;
  font-size: 0.95rem;
  box-shadow:
    inset 18px 0 20px -10px rgba(0,0,0,.55),
    inset -2px 0 6px -2px rgba(0,0,0,.18),
    5px 10px 30px rgba(44, 44, 36, 0.32);
  transition: var(--transition);
}

.book-cover-gen::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(160deg, rgba(255,255,255,.08) 0%, transparent 45%, rgba(0,0,0,.15) 100%);
  pointer-events: none;
}

.book-cover-gen::after {
  content: "";
  position: absolute;
  inset: 7px;
  z-index: 1;
  border: 1px solid rgba(255,255,255,.22);
  box-shadow: inset 0 0 0 3px rgba(255,255,255,.07);
  border-radius: 4px;
  pointer-events: none;
}

.book-cover-gen > * { position: relative; z-index: 2 }

.book-cover-gen.cover-poetry {
  box-shadow:
    inset 10px 0 14px -8px rgba(0,0,0,.1),
    3px 5px 18px rgba(44, 44, 36, 0.18);
  border: 1px solid rgba(0,0,0,.07);
}

.book-cover-gen.cover-poetry::after {
  border-color: rgba(0,0,0,.12);
  box-shadow: inset 0 0 0 3px rgba(0,0,0,.04);
}

.cover-band {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 3;
  background: var(--cover-band-bg, rgba(0,0,0,0.4));
  color: var(--cover-band-fg, rgba(255,255,255,0.9));
  font-family: 'Nunito', sans-serif;
  font-size: 0.6em;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 5px 8px;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cover-top-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
}

.cover-title {
  font-family: 'Oswald', system-ui, sans-serif;
  font-weight: 700;
  font-size: 1em;
  color: #f1d38e;
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.3;
}

.book-cover-gen.cover-poetry .cover-title {
  font-style: italic;
  color: var(--forest);
}

.cover-decoration {
  flex: 0 0 auto;
  height: 1px;
  width: 38%;
  background: rgba(255,255,255,.32);
}

.book-cover-gen.cover-poetry .cover-decoration { background: rgba(44,44,36,.22) }

.cover-author {
  font-family: 'Nunito', sans-serif;
  font-size: 0.7em;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  opacity: .85;
}

.book-large { width: 240px }
.book-medium { width: 140px; margin: 0 auto }
.book-sidebar { width: 100%; max-width: 220px; margin: 0 auto }

.featured-book-output .book-cover-gen,
.book-large .book-cover-gen { font-size: 1.05rem }
.book-sidebar .book-cover-gen { font-size: 0.85rem }
.book-medium .book-cover-gen { font-size: 0.68rem }

/* 13. FEATURED / HOME
   ============================================================ */
/* The cover and the copy sit side by side WHEN THERE IS ROOM FOR BOTH, and
   stack when there is not. It is `flex-wrap` that decides, not a viewport
   width, because the viewport is not what constrains this card: it lives in
   the middle track of a three column grid with a 264px rail on one side and a
   330px rail on the other, so at 1280px it has about 510px to work with, not
   1280.

   The old rule pinned the cover at `flex: 0 0 240px` from 768px up and let the
   copy take whatever was left. Measured, what was left was:

       768px  ->  134px   (one word per line)
       900px  ->  266px
      1023px  ->  389px
      1024px  ->  119px   worst on the site: the three column grid starts here
      1280px  ->  232px

   The 1024px cliff is iPad landscape and every 13" laptop. A container query
   would say this more directly, but wrap plus a flex-basis floor on the copy
   needs no new syntax and degrades the same way: below 180 + 32 + 280 the copy
   drops to its own full width line instead of being crushed. */
.featured-container {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s5) var(--s6);
  align-items: center;
}

.featured-book-output {
  /* Shrinkable. `0 0 240px` is what made this rigid enough to crush its
     sibling; the cover has an aspect-ratio so it scales cleanly. */
  flex: 0 1 180px;
  width: 180px;
  max-width: 100%;
  perspective: 1000px;
}

.featured-content {
  /* The floor that triggers the wrap. Below this the copy is not worth
     setting beside anything. */
  flex: 1 1 280px;
  min-width: 0;
}

.featured-title {
  font-size: var(--t-xl);
  margin: var(--s2) 0 var(--s1);
  text-wrap: balance;
}

.featured-byline {
  font-weight: 500;
  margin: 0;
}

.featured-blurb {
  font-family: 'Nunito', sans-serif;
  font-size: var(--t-xs);
  color: var(--muted-fg);
  line-height: 1.65;
  margin: var(--s3) 0 var(--s4);
}

@media (min-width: 768px) {
  .featured-book-output { width: 200px; flex-basis: 200px }
  .featured-title { font-size: var(--t-2xl) }
}

/* 14. CONTEXT BOX
   ============================================================ */
.context-box {
  margin-top: 36px;
  padding: 28px;
  background: var(--muted);
  border-radius: 20px;
  border: 1px solid var(--border);
  position: relative;
  overflow: hidden;
}

.quote-mark {
  position: absolute;
  top: -10px;
  right: 16px;
  font-size: 7rem;
  color: rgba(93, 112, 82, 0.1);
  font-family: 'Oswald', system-ui, sans-serif;
  line-height: 1;
}

.context-label {
  font-family: 'Nunito', sans-serif;
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--secondary);
  margin-bottom: 10px;
  margin-top: 0;
}

/* 15. SIDEBAR NAVIGATION
   ============================================================ */
aside .nav-link,
.sidebar-nav-item {
  display: block;
  padding: 6px 10px;
  font-family: 'Nunito', sans-serif;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg) !important;
  border-radius: 8px;
  transition: var(--transition);
}

aside .nav-link:hover,
.sidebar-nav-item:hover {
  color: var(--primary) !important;
  background: rgba(93, 112, 82, 0.08);
  padding-left: 14px;
}

.detail-item {
  font-family: 'Nunito', sans-serif;
  font-size: 0.875rem;
  color: var(--fg);
  border-bottom: 1px solid var(--muted);
  padding-bottom: 8px;
  margin-bottom: 10px;
}

.detail-item strong {
  display: block;
  font-size: 0.62rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted-fg);
  margin-bottom: 2px;
}

/* 16. CURATOR / QUOTE BOX
   ============================================================ */
.curator-box .curator-title {
  font-family: 'Nunito', sans-serif;
  color: var(--muted-fg);
  margin-top: 0;
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  border-bottom: 1px solid var(--border);
  padding-bottom: 8px;
  margin-bottom: 14px;
}

.curator-box .curator-text {
  font-style: italic;
  font-size: 0.9rem;
  line-height: 1.65;
  margin-bottom: 12px;
  color: var(--fg);
}

.curator-box .curator-attribution {
  display: block;
  font-family: 'Nunito', sans-serif;
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--secondary);
  text-align: right;
}

.bookshop-widget-card {
  padding: 0 !important;
  overflow: hidden;
}

.bookshop-widget-card .curator-title {
  font-family: 'Nunito', sans-serif;
  color: var(--muted-fg);
  margin: 0;
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  border-bottom: 1px solid var(--border);
  padding: 14px 16px;
}

.bookshop-widget-card iframe,
.bookshop-widget-card > div,
.bookshop-widget-card > script + * {
  width: 100% !important;
  max-width: 100% !important;
  display: block;
}

/* 17. SEARCH RESULTS
   ============================================================ */
.search-results-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 24px;
}

.search-result-item {
  justify-content: space-between;
  height: 100%;
}

.result-title {
  font-family: 'Oswald', system-ui, sans-serif;
  margin: 10px 0;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--fg);
}

.result-meta { padding: 10px 0 0 }

.author-subtext {
  font-family: 'Nunito', sans-serif;
  font-size: 0.8rem;
  color: var(--muted-fg);
  margin-bottom: 10px;
}

.award-tag {
  font-family: 'Nunito', sans-serif;
  font-size: 0.65rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--secondary);
}

.winner-year {
  margin-top: auto;
  border-top: 1px solid var(--muted);
  padding-top: 10px;
  font-family: 'Nunito', sans-serif;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--primary);
}

.empty-state {
  text-align: center;
  padding: 60px 0;
}

.empty-text {
  font-size: 1rem;
  color: var(--muted-fg);
  margin-bottom: 28px;
}

/* 18. CONTENT BODY
   ============================================================ */
.content-body {
  font-family: 'Nunito', sans-serif;
  font-size: 0.97rem;
  line-height: 1.85;
  color: var(--fg);
}

.content-body h3 {
  font-family: 'Oswald', system-ui, sans-serif;
  color: var(--heading);
  margin-top: 36px;
  font-size: 1.15rem;
  font-weight: 700;
}

/* 19. FOOTER — moss green with rounded top
   ============================================================ */
.footer-card {
  /* --footer-bg, not --primary. The footer is the one place on the site that
     sets pale type on a colour, and --primary is too light to carry it: at
     the opacities used here every string in the footer ran 2.44–3.78:1 and
     not one of them passed, on every page. The deeper ground plus the lifted
     opacities above put the whole footer between 5.1 and 8.1. */
  background-color: var(--footer-bg);
  color: var(--primary-fg);
  margin-top: 48px;
  border-radius: 40px 40px 0 0;
  overflow: hidden;
  position: relative;
}

.footer-ornament {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 28px 5% 0;
}

.footer-ornament-line {
  flex: 1;
  height: 1px;
  background: rgba(243, 244, 241, 0.2);
  display: block;
}

.footer-ornament-diamond {
  font-family: 'Nunito', sans-serif;
  color: rgba(243, 244, 241, 0.4);
  font-size: 0.6rem;
  letter-spacing: 0.4em;
  white-space: nowrap;
}

/* Override wrapper inside footer */
.footer-card .wrapper.footer-grid {
  max-width: 100%;
  padding: 36px 5% 44px;
  margin: 0;
}

.footer-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 36px;
  align-items: start;
}

@media (min-width: 768px) {
  .footer-grid { grid-template-columns: 1fr 1fr 1fr }
}

@media (min-width: 1024px) {
  .footer-grid { grid-template-columns: 1.6fr repeat(5, 1fr) }
}

.footer-heading-main {
  font-family: 'Oswald', system-ui, sans-serif;
  color: var(--primary-fg);
  margin-top: 0;
  font-size: 1.4rem;
  font-weight: 700;
}

.footer-category {
  font-family: 'Nunito', sans-serif;
  font-size: 0.65rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: rgba(243, 244, 241, 0.85);
  margin-bottom: 12px;
  border-bottom: 1px solid rgba(243, 244, 241, 0.15);
  padding-bottom: 8px;
}

.footer-description {
  font-family: 'Nunito', sans-serif;
  font-size: 0.875rem;
  line-height: 1.7;
  margin-bottom: 20px;
  color: rgba(243, 244, 241, 0.9);
}

.footer-list {
  list-style: none;
  padding: 0;
  margin: 0;
  font-family: 'Nunito', sans-serif;
  font-size: 0.875rem;
  line-height: 2.4;
}

.footer-link {
  color: rgba(243, 244, 241, 0.86);
  transition: var(--transition);
}

.footer-link:hover {
  color: var(--primary-fg);
  padding-left: 6px;
}

.footer-search {
  border-top: 1px solid rgba(243, 244, 241, 0.15);
  padding: 28px 5%;
  text-align: center;
}

.footer-search-label {
  font-family: 'Nunito', sans-serif;
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: rgba(243, 244, 241, 0.82);
  margin: 0 0 14px;
}

.footer-search iframe,
.footer-search > div,
.footer-search > script + * {
  max-width: 560px !important;
  width: 100% !important;
  margin: 0 auto !important;
  display: block !important;
}

.footer-bottom {
  border-top: 1px solid rgba(243, 244, 241, 0.15);
  padding: 20px 5%;
  text-align: center;
}

.footer-copy {
  font-family: 'Nunito', sans-serif;
  font-size: 0.78rem;
  color: rgba(243, 244, 241, 0.82);
  margin: 0;
}

.footer-bottom-link {
  color: rgba(243, 244, 241, 0.88);
  margin-left: 12px;
  transition: var(--transition);
}

.footer-bottom-link:hover { color: var(--primary-fg) }

/* 20. MOBILE HEADER
   ============================================================ */
@media (max-width: 639px) {
  .site-header { padding: 8px 12px }

  .header-inner {
    padding: 0 8px 0 12px;
    height: 52px;
  }

  .logo-text { font-size: 1.05rem }
  .logo-icon { width: 30px; height: 30px }
  .logo-icon svg { width: 23px; height: 23px }

  .header-left .nav-link { font-size: 0.82rem; padding: 5px 10px }
}

/* 21. TABLET LAYOUT (768px – 1023px)
   ============================================================ */
@media (min-width: 768px) and (max-width: 1023px) {
  /* 2-column grid: narrow sidebar + fluid main area.
     The footer reuses .wrapper as .footer-grid — exclude it, or these
     page-layout rules override the footer's own 3-column tablet grid. */
  .wrapper:not(.single-col):not(.footer-grid) {
    grid-template-columns: 220px 1fr;
  }

  /* The right hand rail drops to its own full-width row.
     Targeted by CLASS, not :nth-child(3). The source order of these pages is
     now content first (see the ordering block below), so a positional
     selector would pick whichever block happened to be third in the markup
     rather than the one this rule is about. */
  .wrapper > .right-sidebar,
  .wrapper > .home-rail-right {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 16px;
    align-items: start;
  }

  .wrapper > .right-sidebar > .sidebar-card,
  .wrapper > .home-rail-right > .sidebar-card {
    margin-bottom: 0;
  }

  /* Search results: slightly smaller cards on tablet */
  .search-results-grid {
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  }
}

/* 21b. SOURCE ORDER vs. VISUAL ORDER
   ------------------------------------------------------------------
   The book page and the home page are both written CONTENT FIRST:

       <div class="main-card">   /  <div class="home-main">
       <aside class="left-sidebar">  /  <aside class="home-rail-left">
       <aside class="right-sidebar"> /  <aside class="home-rail-right">

   because the single column grid stacks in source order, and with the rails
   written first a phone visitor met the navigation before the content. The
   home page h1 began at y=1611 on an 812px viewport and the book page h1 at
   y=1031 — both below the fold, both under a wall of links. The same source
   order is what a screen reader and the keyboard follow, which is why the 4th,
   5th and 6th tab stops on a book page used to be three buy buttons reached
   before the reader had been told what the book was.

   From 768px up there are columns to put things in, so `order` restores the
   left / centre / right arrangement. Nothing moves on a large screen; the fix
   is entirely in the small one.
   ============================================================ */
@media (min-width: 768px) {
  .wrapper > .left-sidebar,
  .wrapper > .home-rail-left   { order: 1 }
  .wrapper > .main-card,
  .wrapper > .home-main        { order: 2 }
  .wrapper > .right-sidebar,
  .wrapper > .home-rail-right  { order: 3 }
}

/* ==========================================================================
   404 page (errors/not_found)
   Mobile first: base styles target small screens, then widen at 768px.
   ========================================================================== */

.error-title {
  font-size: 2.1rem;
}

.error-body {
  font-size: 1.05rem;
  line-height: 1.8;
  color: var(--slate);
  margin-top: 28px;
}

.error-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 32px;
}

/* Full width tap targets on narrow screens, side by side once there is room. */
.error-actions .btn {
  flex: 1 1 100%;
  text-align: center;
}

.error-search {
  margin-top: 40px;
  padding-top: 32px;
  border-top: 1px solid var(--sand);
}

.error-search-row {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 12px;
}

.error-search-input {
  flex: 1;
  padding: 14px 16px;
  font-family: inherit;
  /* 1rem keeps iOS Safari from zooming the viewport on focus. */
  font-size: 1rem;
  color: var(--slate);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  transition: var(--transition);
}

/* Same as .search-input: the ring comes from the global :focus-visible rule,
   and these are the extras on top of it rather than a substitute. */
.error-search-input:focus {
  border-color: var(--primary);
  box-shadow: var(--shadow-card);
}

.error-search-input::placeholder {
  color: var(--clay);
}

.error-awards {
  margin-top: 40px;
  padding-top: 32px;
  border-top: 1px solid var(--sand);
}

.error-awards-heading {
  font-size: 1.25rem;
  color: var(--heading);
  margin-bottom: 18px;
}

.error-awards-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px;
  list-style: none;
  padding: 0;
  margin: 0;
}

.error-awards-list li a {
  display: block;
  /* 44px minimum touch target. */
  padding: 12px 14px;
  font-size: 0.98rem;
  color: var(--slate);
  text-decoration: none;
  border-radius: 6px;
  transition: var(--transition);
}

.error-awards-list li a:hover,
.error-awards-list li a:focus {
  background: var(--accent);
  color: var(--primary);
}

@media (min-width: 768px) {
  .error-title {
    font-size: 3rem;
  }

  .error-actions .btn {
    flex: 0 0 auto;
  }

  .error-search-row {
    flex-direction: row;
    align-items: center;
  }

  .error-awards-list {
    grid-template-columns: repeat(2, 1fr);
    gap: 4px 24px;
  }
}

@media (min-width: 1024px) {
  .error-awards-list {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* ==========================================================================
   Contact page — the email block is the whole point of the page, so it gets
   the visual weight rather than sitting inline in a paragraph.
   ========================================================================== */

.contact-email-block {
  margin: 32px 0 8px;
  padding: 24px 20px;
  background: var(--accent);
  border-radius: 10px;
  text-align: center;
}

.contact-email {
  margin: 12px 0 6px;
  /* Long address must not force the page sideways on a narrow screen. */
  word-break: break-word;
}

.contact-email-link {
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--primary);
  text-decoration: none;
  border-bottom: 2px solid var(--secondary);
  /* 44px tap target on touch screens. */
  display: inline-block;
  padding: 8px 4px;
  transition: var(--transition);
}

.contact-email-link:hover,
.contact-email-link:focus {
  color: var(--secondary);
}

.contact-email-note {
  margin: 0;
  font-size: 0.95rem;
  color: var(--clay);
}

@media (min-width: 768px) {
  .contact-email-block {
    padding: 32px;
  }

  .contact-email-link {
    font-size: 1.45rem;
  }
}

/* ==========================================================================
   Year pages (/year/1995) — a cross award view of one year.
   Mobile first: rows stack, then become two columns once there is room.
   ========================================================================== */

.year-intro {
  margin-top: 18px;
  font-size: 1.05rem;
  line-height: 1.7;
  color: var(--slate);
}

.year-section {
  margin-top: 40px;
}

.year-section-title {
  font-size: 1.4rem;
  color: var(--heading);
  margin-bottom: 6px;
}

.year-section-note {
  margin: 0 0 16px;
  font-size: 0.98rem;
  color: var(--clay);
}

.year-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.year-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 14px 0;
  border-bottom: 1px solid var(--border-light, var(--sand));
}

.year-row:last-child {
  border-bottom: none;
}

.year-award-link {
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--secondary);
  text-decoration: none;
  font-weight: 700;
}

.year-award-link:hover,
.year-award-link:focus {
  color: var(--primary);
}

/* Not a link: these books won nothing, so there is no award page to visit. */
.year-award-muted {
  color: var(--clay);
  font-weight: 600;
}

.year-book-link {
  font-size: 1.08rem;
  color: var(--slate);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: var(--transition);
}

.year-book-link:hover,
.year-book-link:focus {
  color: var(--primary);
  border-bottom-color: var(--secondary);
}

.year-book-author {
  display: block;
  font-size: 0.95rem;
  color: var(--clay);
}

.year-nav {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 40px;
  padding-top: 24px;
  border-top: 1px solid var(--sand);
}

.year-nav-side {
  flex: 1;
}

.year-nav-right {
  text-align: right;
}

@media (min-width: 768px) {
  .year-row {
    flex-direction: row;
    align-items: baseline;
    gap: 20px;
  }

  /* Fixed award column so the titles line up down the page. */
  .year-row-award {
    flex: 0 0 230px;
  }

  .year-row-book {
    flex: 1;
  }

  .year-book-author {
    display: inline;
    margin-left: 8px;
  }
}

/* Year links in the award list table and the book page sidebar. Kept subtle so
   the table still reads as data rather than a wall of links. */
.year-col-link,
.sidebar-title-link {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dotted var(--border);
  transition: var(--transition);
}

.year-col-link:hover,
.year-col-link:focus,
.sidebar-title-link:hover,
.sidebar-title-link:focus {
  color: var(--primary);
  border-bottom-color: var(--secondary);
}

/* ==========================================================================
   Prize facts block (award list pages) and the announcement calendar
   (/schedule). Mobile first throughout.
   ========================================================================== */

.prize-facts {
  margin: 32px 0 8px;
  padding: 24px 20px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
}

.prize-facts-title {
  font-size: 1.25rem;
  color: var(--heading);
  margin: 0 0 18px;
}

.prize-facts-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  margin: 0 0 20px;
}

.prize-fact dt {
  font-size: 0.75rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--clay);
  margin-bottom: 2px;
}

.prize-fact dd {
  margin: 0;
  font-size: 1rem;
  color: var(--slate);
  font-weight: 600;
}

.prize-facts-detail h3 {
  font-size: 1rem;
  color: var(--heading);
  margin: 18px 0 4px;
}

.prize-facts-detail p {
  margin: 0;
  font-size: 0.98rem;
  line-height: 1.7;
  color: var(--slate);
}

.prize-facts-link {
  color: var(--primary);
}

.prize-facts-source {
  margin-top: 18px !important;
  padding-top: 14px;
  border-top: 1px solid var(--sand);
  font-size: 0.88rem !important;
  color: var(--clay) !important;
}

.schedule-month {
  margin-top: 34px;
}

.schedule-month-name {
  font-size: 1.5rem;
  color: var(--heading);
  padding-bottom: 8px;
  border-bottom: 2px solid var(--sand);
}

.schedule-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.schedule-row {
  padding: 16px 0;
  border-bottom: 1px solid var(--border-light, var(--sand));
}

.schedule-row:last-child {
  border-bottom: none;
}

.schedule-award {
  margin: 0 0 4px;
  font-size: 1.1rem;
}

.schedule-award-link {
  color: var(--slate);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: var(--transition);
}

.schedule-award-link:hover,
.schedule-award-link:focus {
  color: var(--primary);
  border-bottom-color: var(--secondary);
}

.schedule-when {
  margin: 0 0 4px;
  font-size: 0.98rem;
  line-height: 1.6;
  color: var(--slate);
}

.schedule-meta {
  margin: 0;
  font-size: 0.88rem;
  color: var(--clay);
}

.schedule-note {
  margin-top: 40px;
  padding: 20px;
  background: var(--accent);
  border-radius: 10px;
  font-size: 0.92rem;
  line-height: 1.7;
  color: var(--slate);
}

.schedule-note p {
  margin: 0 0 10px;
}

.schedule-note p:last-child {
  margin-bottom: 0;
}

@media (min-width: 768px) {
  .prize-facts {
    padding: 30px;
  }

  .prize-facts-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 18px 30px;
  }
}

@media (min-width: 1024px) {
  .prize-facts-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* --------------------------------------------------------------------------
   Subject browse (/subjects and /subject/:slug)

   The row component is the same shape as the year page rows: a short meta
   column and a book column, stacked on mobile and side by side from 768px up.
   -------------------------------------------------------------------------- */

.subject-stats {
  font-size: 0.9rem;
  color: var(--clay);
  margin: 0 0 18px;
}

.subject-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.subject-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 14px 0;
  border-bottom: 1px solid var(--border-light, var(--sand));
}

.subject-row:last-child {
  border-bottom: none;
}

.subject-row-meta {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.subject-year {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--primary);
}

.subject-award {
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--clay);
}

/* MULTI PRIZE WINNER PAGES
   Reuses .subject-list and .subject-row wholesale. These rules are the only
   additions, and the wrap is load bearing: a subject row carries one award
   label, a multi prize row carries two or three, and "National Book Award for
   Non-Fiction 1988" beside "Pulitzer Prize for History 1988" overflows a phone
   on one line. Mobile first, per CLAUDE.md.
   ============================================================ */
.multi-prize-list .subject-row-meta {
  flex-wrap: wrap;
  row-gap: 4px;
}

.multi-prize-group {
  margin-top: 36px;
}

.multi-prize-group:first-of-type {
  margin-top: 20px;
}

.multi-prize-summary {
  font-family: 'Nunito', sans-serif;
  font-size: 0.88rem;
  line-height: 1.7;
  color: var(--muted-fg);
  margin: 6px 0 0;
  max-width: 640px;
}

/* The link into a book's pairing page, under "Also Recognised By". Its own rule
   above it so it does not read as another appearance in that list. */
.appearance-pairing {
  margin: 10px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--border-light);
  font-size: 0.85rem;
  line-height: 1.6;
}

@media (min-width: 768px) {
  .multi-prize-summary {
    font-size: 0.92rem;
  }
}

/* Chips: the bounded link sets. Tap targets stay at 44px of vertical reach on
   mobile via the padding, which is the smallest comfortable size. */
.subject-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.subject-chip {
  display: inline-block;
  padding: 8px 14px;
  border: 1px solid var(--sand);
  border-radius: 999px;
  background: var(--bg);
  color: var(--slate);
  font-size: 0.85rem;
  text-decoration: none;
  transition: var(--transition);
}

.subject-chip:hover,
.subject-chip:focus {
  border-color: var(--secondary);
  color: var(--primary);
}

.subject-sources {
  margin-top: 36px;
  padding-top: 24px;
  border-top: 1px solid var(--sand);
}

.subject-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  margin-top: 28px;
}

.subject-card {
  padding: 20px;
  border: 1px solid var(--sand);
  border-radius: 8px;
  background: var(--card);
}

.subject-card-title {
  margin: 0 0 4px;
  font-size: 1.15rem;
}

.subject-card-link {
  color: var(--slate);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: var(--transition);
}

.subject-card-link:hover,
.subject-card-link:focus {
  color: var(--primary);
  border-bottom-color: var(--secondary);
}

.subject-card-count {
  margin: 0 0 10px;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--clay);
}

.subject-card-desc {
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--clay);
}

@media (min-width: 768px) {
  .subject-row {
    flex-direction: row;
    align-items: baseline;
    gap: 20px;
  }

  /* Fixed meta column so the titles line up down the page, matching the year
     pages. Wider than the year column because it carries the prize name too. */
  .subject-row-meta {
    flex: 0 0 260px;
  }

  .subject-row-book {
    flex: 1;
  }

  .subject-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .subject-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Year snippet on the year pages, and the /years decade hub. */

.year-book-summary {
  margin: 6px 0 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--clay);
}

.decade-section {
  margin-top: 30px;
}

.decade-year-row {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-top: 14px;
}

.decade-year {
  display: block;
  padding: 12px 14px;
  border: 1px solid var(--sand);
  border-radius: 8px;
  background: var(--bg);
  text-decoration: none;
  transition: var(--transition);
}

.decade-year:hover,
.decade-year:focus {
  border-color: var(--secondary);
  background: var(--card);
}

.decade-year-number {
  display: block;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--primary);
}

.decade-year-count {
  display: block;
  font-size: 0.78rem;
  color: var(--clay);
}

@media (min-width: 480px) {
  .decade-year-row {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 768px) {
  .decade-year-row {
    grid-template-columns: repeat(5, 1fr);
  }

  /* The summary sits under the title in the book column, so it should not
     stretch the full width of a wide screen. */
  .year-book-summary {
    max-width: 60ch;
  }
}

/* Hand written year context. The lead sits above the winners table, the longer
   block below it. */

.year-stats {
  font-size: 0.85rem;
  color: var(--clay);
  margin: 10px 0 0;
}

.year-context {
  background: var(--card);
  border-left: 3px solid var(--secondary);
  border-radius: 0 8px 8px 0;
  padding: 20px;
}

.year-context-body {
  margin: 0;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--slate);
}

@media (min-width: 768px) {
  .year-context {
    padding: 26px 30px;
  }

  .year-context-body {
    max-width: 70ch;
  }
}

/* WorldCat library lookup on book pages. An outlined button rather than a
   filled one: it must read as clickable, since it was invisible as a text link,
   but it earns no commission so it should not compete with the two above it. */

.library-link {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border-light, var(--sand));
}

.library-note {
  margin: 6px 0 0;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--clay);
}

/* Free full text for the public domain books. Mirrors .library-link exactly:
   both sit below the affiliate buttons, both earn nothing, and both must still
   read as clickable. Mobile first — nothing to override at wider breakpoints,
   because the sidebar column only changes width. */

.free-read {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border-light, var(--sand));
}

.free-read-note {
  margin: 6px 0 0;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--clay);
}

/* /free-classic-books. Mobile first: the row stacks and the free link sits
   under the title, so the two tap targets never crowd each other at 390px. */

.free-read-era { margin-top: 28px }

.free-read-era-count {
  font-weight: 400;
  color: var(--clay);
}

.free-read-inline {
  display: inline-block;
  margin-top: 4px;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--primary);
  text-decoration: underline;
}

@media (min-width: 768px) {
  .free-read-inline { margin-left: 10px; margin-top: 0 }
}

/* The reason line under a read alike recommendation. An unexplained
   suggestion is indistinguishable from the random card this replaced, so the
   shared subject is always stated. Quiet: it supports the title, it does not
   compete with it. */

.read-alike-reason {
  display: block;
  margin-top: 2px;
  font-size: 0.72rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--clay);
}

/* Stated once above the list when all five recommendations share a subject,
   which is 95% of book pages. */

.read-alike-lede {
  margin: -4px 0 10px;
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--clay);
}

/* Book page prose. Expanded summaries run past 250 words, so the copy is stored
   with paragraph breaks and rendered as paragraphs: one 300 word block is a
   wall of text on a phone. Books not yet expanded hold no blank line and render
   as a single paragraph, so these rules are safe across the whole catalogue. */

.book-summary p {
  font-size: 1.1rem;
  color: var(--slate);
  line-height: 1.6;
  margin: 0 0 1rem;
}

.book-summary p:last-child { margin-bottom: 0 }

/* Summary collapse — clamp the summary, lift the Historical Context box.

   Every summary now runs 255 words or more (median 281). On a phone that is
   twenty five lines and more before the context box begins, so the context was
   effectively unreachable without a long scroll.

   The full text is always in the HTML and only CSS clips it, which is what keeps
   this SEO-safe: content inside a collapsed region is indexed and weighted
   normally so long as the crawler receives it in the markup. Do not replace this
   with a server side truncate or an AJAX load.

   Collapsed by DEFAULT in CSS, not by JavaScript on connect. A JS collapse would
   paint the full summary and then shrink it, which is a layout shift on every
   book page. Mobile first: the clamp is tightest where the problem is worst. */

.summary-collapse {
  position: relative;
}

/* Visually hidden, still focusable and still operable by keyboard. */
.summary-expand-input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.book-summary {
  position: relative;
  max-height: 15.5em;
  overflow: hidden;
}

.summary-expand-input:checked ~ .book-summary {
  max-height: none;
  overflow: visible;
}

/* Fade the clipped edge so it reads as "there is more" rather than as a
   sentence that stops mid air. Sits above the text, never eats clicks. */
.book-summary::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 4.5em;
  background: linear-gradient(to bottom, rgba(245, 241, 235, 0), var(--card) 85%);
  pointer-events: none;
}

.summary-expand-input:checked ~ .book-summary::after { content: none }

.summary-expand-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.9rem;
  padding: 0.5rem 0.95rem;
  font-family: 'Nunito', sans-serif;
  font-size: 0.85rem;
  font-weight: 700;
  /* --primary-dark: this pill sits on --accent (#E6DCCD), where --primary is
     3.96:1. It is also a 44px tall control, so it doubles as the tap target
     rule for the one interactive element in the article body. */
  color: var(--primary-dark);
  background: var(--accent);
  border: 1px solid var(--border);
  border-radius: 999px;
  min-height: var(--tap);
  cursor: pointer;
  /* 44px tall including padding: a real tap target on a phone. */
  min-height: 44px;
  transition: background 0.15s ease, color 0.15s ease;
}

/* The label's words live in the markup, not in `content:`. Generated content
   is not reliably part of an element's accessible name, so the visually hidden
   checkbox this label names was announced as an unnamed checkbox. Swapping two
   real spans keeps the wording change and gives the control a name in both
   states — display:none is excluded from the name, so it reads "Read the full
   summary" when collapsed and "Show less" when open. */
.summary-expand-less { display: none }
.summary-expand-input:checked ~ .summary-expand-toggle .summary-expand-more { display: none }
.summary-expand-input:checked ~ .summary-expand-toggle .summary-expand-less { display: inline }

/* The chevron flips when open, so the control states its own direction. */
.summary-expand-toggle::before {
  content: "";
  width: 0.55em;
  height: 0.55em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-0.15em) rotate(45deg);
  transition: transform 0.15s ease;
}

.summary-expand-input:checked ~ .summary-expand-toggle::before {
  transform: translateY(0.1em) rotate(-135deg);
}

.summary-expand-toggle:hover {
  background: var(--muted);
  color: var(--heading);
}

/* Keyboard users get a visible ring: the input is offscreen, so the focus
   style has to be forwarded to the label that stands in for it. */
.summary-expand-input:focus-visible ~ .summary-expand-toggle {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

@media (min-width: 768px) {
  .book-summary { max-height: 19em }
}

@media (min-width: 1025px) {
  .book-summary { max-height: 22em }
}

/* Readers who ask for less motion still get everything, without the movement.
   This block used to cover the summary toggle alone. Everything else on the
   site moved regardless: `html { scroll-behavior: smooth }`, which fires on
   the decade "Jump to" nav and sweeps the viewport across a hundred row
   table — the textbook vestibular trigger; the global `--transition: all
   0.3s ease`; `scale(1.04)` on every button hover; and `translateY(-4px)`
   on every card hover.

   Transitions are neutralised rather than removed so a state change still
   happens, it just happens at once. Transforms are dropped entirely: a
   hover that jumps 4px with no tween is worse than one that does not move,
   and the colour change alone already carries the state. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto }

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .btn:hover,
  .search-submit:hover,
  .card-hover:hover,
  .subject-card:hover,
  .book-link-wrapper:hover .book-cover-gen { transform: none !important }
}

/* Printing a clipped article is never what anyone wants. */
@media print {
  .book-summary { max-height: none; overflow: visible }
  .book-summary::after { content: none }
  .summary-expand-toggle { display: none }
}

.context-prose p {
  position: relative;
  z-index: 1;
  font-size: 0.95rem;
  margin: 0 0 0.85rem;
}

.context-prose p:last-child { margin-bottom: 0 }

/* ============================================================
   23. HOME PAGE SHELVES
   ------------------------------------------------------------------
   The centre column used to hold the book of the day and nothing else.
   Measured at 1440px it ran 491px tall against a 1,642px right rail,
   leaving roughly 1,100px of empty parchment under the only editorial
   content on the site's strongest page.

   Everything here is data the site already computed and never showed. It
   also fixes a crawl problem: the year pages, the multi prize pages and
   the free reads were reachable from book pages and the footer but not
   from the home page, so the pages with the least authority were the
   furthest from the page with the most.
   ============================================================ */
.home-main {
  display: flex;
  flex-direction: column;
  gap: var(--s5);
  min-width: 0;
}

.home-shelf {
  background: var(--card);
  border: 1px solid rgba(222, 216, 207, 0.65);
  border-radius: var(--r-lg);
  padding: var(--s5);
}

@media (min-width: 768px) {
  .home-shelf { padding: var(--s6) }
  .home-main  { gap: var(--s6) }
}

/* Heading and its "see all" link share a baseline and split to two lines
   only when the heading genuinely needs the width. */
.shelf-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s2) var(--s4);
  margin-bottom: var(--s2);
}

.shelf-title {
  font-size: var(--t-lg);
  margin: 0;
  text-wrap: balance;
}

/* Underlined, and in the moss rather than inheriting: this is a link inside
   a heading row, and a link nobody recognises as a link earns no clicks —
   the same lesson the WorldCat button learned the hard way. */
.shelf-more {
  font-family: 'Nunito', sans-serif;
  font-size: var(--t-2xs);
  font-weight: 700;
  color: var(--primary);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 2px;
  white-space: nowrap;
  padding: var(--s1) 0;
}

.shelf-more::after { content: " →" }
.shelf-more:hover, .shelf-more:focus { color: var(--secondary) }

.shelf-lede {
  font-family: 'Nunito', sans-serif;
  font-size: var(--t-xs);
  color: var(--muted-fg);
  line-height: 1.6;
  margin: 0 0 var(--s4);
  max-width: 60ch;
}

/* Cover shelf — auto-fill so it reflows rather than overflowing. minmax at
   96px means three across on the narrowest phone and six on a wide desktop,
   with no width ever producing an orphan on its own row. */
.cover-shelf {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: var(--s4);
}

@media (min-width: 480px) {
  .cover-shelf { grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)) }
}

.cover-shelf-item { min-width: 0 }

.cover-shelf-link {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}

.cover-shelf-link .book-cover-gen { font-size: 0.6rem }

.cover-shelf-link:hover .book-cover-gen {
  transform: translateY(-3px);
  transition: var(--transition);
}

.cover-shelf-caption {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.cover-shelf-title {
  font-family: 'Oswald', system-ui, sans-serif;
  font-size: var(--t-2xs);
  font-weight: 600;
  color: var(--heading);
  line-height: 1.25;
}

.cover-shelf-award {
  font-family: 'Nunito', sans-serif;
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--muted-fg);
  line-height: 1.3;
}

.cover-shelf-link:hover .cover-shelf-title { color: var(--secondary) }

/* Row shelves (multi prize, free reads) reuse the sidebar list primitives so
   a row looks the same wherever it appears. */
.shelf-rows { margin: 0 }

.shelf-row-meta {
  display: block;
  font-family: 'Nunito', sans-serif;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--secondary);
  margin-top: 3px;
}

/* Year strip — the shortest path from the home page to a year page, which
   nothing on the home page linked to before. */
.year-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2) var(--s4);
  padding: var(--s4) var(--s5);
  background: var(--accent);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}

.year-strip-label {
  font-family: 'Nunito', sans-serif;
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted-fg);
  white-space: nowrap;
}

.year-strip-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1) var(--s2);
}

.year-strip-link {
  font-family: 'Oswald', system-ui, sans-serif;
  font-size: var(--t-2xs);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--primary-dark);
  padding: var(--s1) var(--s3);
  border-radius: var(--r-pill);
  transition: var(--transition);
}

.year-strip-link:hover,
.year-strip-link:focus {
  background: var(--card);
  color: var(--secondary);
}

.year-strip-all { text-decoration: underline; text-underline-offset: 3px }

/* ============================================================
   24. SHARED LIST PRIMITIVES
   ------------------------------------------------------------------
   These replace 17 inline style attributes on the book page and the ones
   the home page carried. Same three decisions repeated: reset a list,
   separate its rows, stack a card under the one above it.
   ============================================================ */
.card-stack { margin-top: var(--s5) }

.stack-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.stack-list-spaced { margin-bottom: var(--s4) }

.stack-item {
  padding: 6px 0;
  border-bottom: 1px solid var(--border-light);
}

.stack-item:last-child { border-bottom: none }

/* Sidebar group labels. Were five copies of
   style="font-size: 0.75rem; color: var(--gold); margin-top: 15px" per rail. */
.sidebar-group-label {
  font-family: 'Nunito', sans-serif;
  font-size: var(--t-2xs);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--secondary);
  margin: var(--s4) 0 var(--s2);
}

.sidebar-nav-group {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  margin-bottom: var(--s5);
}

.sidebar-nav-group-last { margin-bottom: 0 }

.sidebar-more {
  margin: var(--s3) 0 0;
  font-size: var(--t-xs);
}

/* ============================================================
   25. SEARCH REFINEMENT
   ------------------------------------------------------------------
   The results page had no search field. A reader who searched "war", got 59
   matches and wanted to narrow it had to go back to the header, open the
   toggle and retype. On a site whose whole job is lookup, the results page
   is the one page that must carry a box.

   The label is a real, visible <label>, not a placeholder and not an
   aria-label: a placeholder disappears the moment someone types, which is
   exactly when they most need to know what the field wants.
   ============================================================ */
.search-refine {
  margin: 0 0 var(--s6);
  padding: var(--s4) 0 0;
  border-top: 1px solid var(--border);
}

.search-refine-label {
  display: block;
  font-family: 'Nunito', sans-serif;
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted-fg);
  margin-bottom: var(--s2);
}

.search-refine-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

.search-refine-input {
  flex: 1 1 220px;
  min-width: 0;
  /* 1rem, so iOS Safari does not zoom the viewport when the field takes
     focus — the same reason .error-search-input sets it. */
  font-family: 'Nunito', sans-serif;
  font-size: 1rem;
  color: var(--fg);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  padding: 0 var(--s5);
  min-height: var(--tap);
  transition: var(--transition);
}

.search-refine-input::placeholder { color: var(--muted-fg) }

.search-refine-input:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 2px;
  border-color: var(--primary);
}

.search-refine-submit {
  flex: 0 0 auto;
  min-height: var(--tap);
}

/* Two results across on a phone. One full width card per row made twelve
   results a very long scroll for what is meant to be a fast lookup, and the
   covers are the fastest way to recognise a book you half remember. */
@media (max-width: 767px) {
  .search-results-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--s3);
  }
  .search-result-item { padding: var(--s3) }
  .search-results-grid .book-medium { width: 100% }

  /* Half the width means the award name and the title both wrap more, so
     both come down a step and tighten up rather than sprawling. */
  .search-results-grid .award-tag {
    font-size: 0.6rem;
    line-height: 1.35;
    letter-spacing: 0.04em;
  }
  .search-results-grid .result-title { font-size: 0.95rem; line-height: 1.25 }
  .search-results-grid .author-subtext { font-size: 0.78rem }
}

/* ============================================================
   26. LINK AFFORDANCE IN RUNNING TEXT
   ------------------------------------------------------------------
   axe: `link-in-text-block`, serious, on six page types. The breadcrumb
   "Home" sat at 1.22:1 against the separator text around it with no
   underline, so nothing but a barely perceptible hue shift said it was
   clickable. The site had already reached this conclusion once — see the
   comment on .list-crosslink-link — and this applies the same rule to the
   places that missed it.
   ============================================================ */
.breadcrumb-nav a,
.breadcrumbs a,
.prize-facts-link,
.prize-facts-source a {
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

.breadcrumb-nav a:hover,
.breadcrumbs a:hover,
.prize-facts-link:hover { text-decoration-thickness: 2px }

/* ============================================================
   27. AWARD TABLE ROW AS A TARGET
   ------------------------------------------------------------------
   The book title link on an award list measured 34x25px at 375px — the
   primary target of the primary journey, well under the 44px minimum. The
   fix is not only bigger text: it is that the whole row is the target, which
   is what a reader already expects from a table of links.

   Done with a stretched pseudo element on the title's own anchor rather than
   a JS row click handler, so it stays one real link with one real href: the
   row is clickable, text in the row is still selectable, and middle click and
   "open in new tab" behave. The year cell links elsewhere, so it is lifted
   above the stretched layer to stay clickable in its own right.
   ============================================================ */
@media (max-width: 767px) {
  .modern-table tbody tr { position: relative }

  .modern-table .title-col .book-link::after {
    content: "";
    position: absolute;
    inset: 0;
    /* Below the year link, above the row background. */
    z-index: 1;
  }

  .modern-table .year-col { position: relative; z-index: 2 }

  .modern-table tbody tr:focus-within { background: rgba(93, 112, 82, 0.06) }
}

/* ============================================================
   28. HEADER SEARCH — OPEN AT DESKTOP
   ------------------------------------------------------------------
   The field was behind a checkbox toggle at every width, including desktop,
   where the header pill carried roughly 600px of empty band between the logo
   and the toggle. On a 1,743 page lookup site search IS the navigation, and
   Jakob's law is unambiguous: readers expect an open field top right.

   Below 768px the toggle stays, because the room genuinely is not there.
   ============================================================ */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The header's three groups must never wrap: at 375px "Home" and "About"
   were breaking onto two lines and squeezing the pill out of shape. */
.header-inner { flex-wrap: nowrap }
.main-nav { display: flex; align-items: center; gap: var(--s1); flex-wrap: nowrap }
.header-left .nav-link { white-space: nowrap }
.logo-text { white-space: nowrap }

@media (min-width: 768px) {
  /* display:none, not just unstyled: it also removes the 0x0 phantom tab stop
     the offscreen checkbox left in the header at every width. */
  .search-container .hidden-checkbox,
  .search-container .search-icon { display: none }

  .search-form {
    width: auto;
    overflow: visible;
    visibility: visible;
    transition: none;
  }

  .search-input { width: 220px }
}

@media (min-width: 1024px) {
  .search-input { width: 260px }
}

/* The submit reads "Search" now rather than "Go", and it is a real target. */
.search-submit {
  min-height: 36px;
  white-space: nowrap;
}

/* ============================================================
   29. FOOTER SEARCH
   ------------------------------------------------------------------
   Replaces the Bookshop.org search widget that used to embed here. See the
   comment in layouts/application.html.erb for what that cost every page.
   ============================================================ */
.footer-search-form {
  max-width: 520px;
  margin: 0 auto;
  text-align: left;
}

.footer-search-label {
  display: block;
  font-family: 'Nunito', sans-serif;
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: rgba(243, 244, 241, 0.82);
  margin: 0 0 var(--s2);
}

.footer-search-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

.footer-search-input {
  flex: 1 1 200px;
  min-width: 0;
  /* 1rem keeps iOS Safari from zooming the viewport on focus. */
  font-family: 'Nunito', sans-serif;
  font-size: 1rem;
  color: var(--fg);
  background: rgba(255, 255, 255, 0.94);
  border: 1px solid rgba(243, 244, 241, 0.3);
  border-radius: var(--r-pill);
  padding: 0 var(--s5);
  min-height: var(--tap);
}

.footer-search-input::placeholder { color: var(--muted-fg) }

/* The ink ring from the global rule is invisible on the deep moss ground, so
   this is the one place that overrides it — with the pale mist instead. */
.footer-search-input:focus-visible,
.footer-search-submit:focus-visible,
.footer-link:focus-visible,
.footer-bottom-link:focus-visible {
  outline: 2px solid var(--primary-fg);
  outline-offset: 2px;
}

.footer-search-submit {
  flex: 0 0 auto;
  min-height: var(--tap);
  cursor: pointer;
}

/* ============================================================
   30. THE 1024–1279 BAND
   ------------------------------------------------------------------
   The three column grid starts at 1024px, and 264 + 330 of rail plus gaps
   and padding left the centre track 254px wide there — narrower than it got
   on a tablet, which is why 1024px measured as the worst width on the site
   rather than the best. iPad landscape and every 13" laptop sit in this band.

   The rails carry nothing but links and hold their shape fine when narrowed;
   the centre column is the one that has to fit prose. So the band trades rail
   width for centre width until there is enough of it to stop trading.
   ============================================================ */
@media (min-width: 1024px) and (max-width: 1279px) {
  .wrapper:not(.single-col):not(.footer-grid) {
    grid-template-columns: 226px 1fr 254px;
    gap: 20px;
  }

  .main-card { padding: 28px }

  /* One step down the scale: at this width the hero is competing with two
     rails for the same eye, and 36px of Oswald wraps to four lines. */
  .featured-title { font-size: var(--t-lg) }
}

/* Two category labels stack under a list in the same footer column. Was an
   inline margin-top on each. */
.footer-category-stacked { margin-top: var(--s5) }

/* ============================================================
   31. HOME MASTHEAD
   ------------------------------------------------------------------
   The page's own heading. Until 2026-09-01 the home page's h1 was the
   featured book's title, which rotated every 24 hours with the book of the
   day: it shared no word with the title tag, so the page sat at the 76%
   baseline title rewrite rate rather than the 20.6% that title and h1
   agreement buys, and it duplicated the h1 of that book's own page. It also
   meant a first time visitor met 21 prize names and one book with nothing
   on the page saying what the site was.
   ============================================================ */
.home-masthead {
  padding: 0 var(--s2) var(--s2);
}

.home-masthead .page-title {
  margin: 0 0 var(--s3);
  text-wrap: balance;
  /* The year range is the reason this heading carries a number at all, so
     keep the digits even on their own baseline. */
  font-variant-numeric: tabular-nums;
}

.home-lede {
  font-family: 'Nunito', sans-serif;
  font-size: var(--t-sm);
  line-height: 1.65;
  color: var(--muted-fg);
  margin: 0;
  max-width: 62ch;
}

@media (min-width: 768px) {
  .home-masthead { padding: 0 var(--s3) var(--s2) }
  .home-lede { font-size: var(--t-md) }
}

/* ============================================================
   32. "FROM THE SHELF" PICK
   ------------------------------------------------------------------
   Replaces the Bookshop.org book widget that sat in this slot until
   2026-09-02. See the comment in index.html.erb, and
   BooksController#shelf_pick for how the book is chosen.
   ============================================================ */
.shelf-pick-link {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  margin-top: var(--s3);
}

.shelf-pick-cover {
  width: 100%;
  max-width: 150px;
  margin: 0 auto var(--s3);
}

.shelf-pick-cover .book-cover-gen { font-size: 0.7rem }

.shelf-pick-link:hover .book-cover-gen {
  transform: translateY(-3px);
  transition: var(--transition);
}

.shelf-pick-title {
  font-family: 'Oswald', system-ui, sans-serif;
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--heading);
  line-height: 1.25;
}

.shelf-pick-link:hover .shelf-pick-title { color: var(--secondary) }

.shelf-pick-reason {
  display: block;
  font-family: 'Nunito', sans-serif;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--secondary);
  margin-top: var(--s1);
}
