@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400;1,700&family=Saira+Condensed:wght@600;700&family=IBM+Plex+Mono:wght@500;600&display=swap');

/* GENERATED by build_site.py from theme/ — DO NOT EDIT HERE.
   Edit theme/base.css, theme/parts/*.css or
   theme/universes/*.css in the author-websites repo and rebuild.
   Brand: davidnairnbooks (davidnairnbooks.com) · layout: singleworld
   Universes: black (default) */

:root {  /* default universe: black */
  --sand:       #0f1318;
  --paper:      #171d24;
  --white:      #171d24;
  --ink:        #dde4ec;
  --sea:        #6fa8c9;
  --sea-fg:     #0f1318;
  --rope:       #7b8794;
  --accent:     #d98324;
  --accent-fg:  #0f1318;
  --muted:      #8d97a3;
  --body:       #a8b3bf;
  --rule:       rgba(255,255,255,0.13);
  --nav-bg:     #070a0d;
  --nav-fg:     #dde4ec;
  --nav-dim:    #8d97a3;
  --nav-cta:    #d98324;
  --nav-track:  .06em;
  --wordmark:      'Saira Condensed', 'Arial Narrow', sans-serif;
  --display:       'Saira Condensed', 'Arial Narrow', sans-serif;
  --label:         'IBM Plex Mono', ui-monospace, Menlo, monospace;
  --wordmark-size: 1.25rem;
  --wordmark-track: .07em;
  --display-track: .03em;
  --label-track:   .04em;
  --label-track-sm: .04em;
  --wallpaper:      url('/images_cache/wallpaper_black_dark.jpg');
  --wallpaper-size: 600px 600px;
  --cover-fallback: #080b0f;
  --placeholder-bg: linear-gradient(160deg, #1d242c, #0f1318);
}
body.uni-black {  /* black */
  --sand:       #0f1318;
  --paper:      #171d24;
  --white:      #171d24;
  --ink:        #dde4ec;
  --sea:        #6fa8c9;
  --sea-fg:     #0f1318;
  --rope:       #7b8794;
  --accent:     #d98324;
  --accent-fg:  #0f1318;
  --muted:      #8d97a3;
  --body:       #a8b3bf;
  --rule:       rgba(255,255,255,0.13);
  --nav-bg:     #070a0d;
  --nav-fg:     #dde4ec;
  --nav-dim:    #8d97a3;
  --nav-cta:    #d98324;
  --nav-track:  .06em;
  --wordmark:      'Saira Condensed', 'Arial Narrow', sans-serif;
  --display:       'Saira Condensed', 'Arial Narrow', sans-serif;
  --label:         'IBM Plex Mono', ui-monospace, Menlo, monospace;
  --wordmark-size: 1.25rem;
  --wordmark-track: .07em;
  --display-track: .03em;
  --label-track:   .04em;
  --label-track-sm: .04em;
  --wallpaper:      url('/images_cache/wallpaper_black_dark.jpg');
  --wallpaper-size: 600px 600px;
  --cover-fallback: #080b0f;
  --placeholder-bg: linear-gradient(160deg, #1d242c, #0f1318);
}
:root {  /* brand structure */
  --content-max: 920px;
  --nav-max: 980px;
  --series-card-gap: 1.25rem;
  --series-card-img-h-sm: 220px;
  --shadow-hover: 0 4px 16px rgba(0,0,0,0.14);
}

/* ═══════════════════════════════════════════════════════════════════════════
   base.css — the shared system behind all four author-brand sites (R2900).

   NOTHING HERE NAMES A COLOUR OR A FACE. Every one comes from a token, and the
   tokens come from theme/universes/<universe>.css: the palette AND the display
   face are per-UNIVERSE, not per-brand, because thebondi and thegoldcoast share
   one byline, one site and one nav bar and take different faces (ruled
   2026-08-30). Colour already themed per universe via body.uni-*; type joins it.

   Compiled — never served. build_site.py concatenates:
       @import <fonts>  ·  :root{default universe}  ·  body.uni-*{each universe}
       ·  this file  ·  the brand's theme/parts/*.css
   into <site>/css/style.css, which the site repo commits. A site stays
   standalone-servable; this repo is only needed to rebuild it.

   Structural values that differ between the two live sites for no reason
   anyone recorded (main 900 vs 920, nav 960 vs 980) are brand tokens holding
   each site's own value, not a unification nobody asked for.
   ═══════════════════════════════════════════════════════════════════════════ */

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

/* Body face is Lora on all five universes and is deliberately NOT a token. The
   house voice is the one thing that must not vary, or five sites by one author
   stop reading as one hand. */
body {
  font-family: 'Lora', Georgia, 'Times New Roman', serif;
  color: var(--ink);
  background-color: var(--sand);
  background-image: var(--wallpaper);
  background-size: var(--wallpaper-size);
  line-height: 1.6;
  font-size: 1rem;
}

/* --wordmark carries the nav brand and the page H1; --display carries the
   heading grid. Separate because a script (Yellowtail) or a blackletter
   (Textura) can carry a wordmark and cannot carry a heading grid. */
h1, .nav-brand { font-family: var(--wordmark); letter-spacing: var(--wordmark-track); }
h2, h3 { font-family: var(--display); letter-spacing: var(--display-track); }

/* ── Navigation ─────────────────────────────────────────── */
/* Was `background: var(--ink)` — the nav colour WAS the body-text colour, so a
   dark ground inverted the nav with it. --nav-bg/--nav-fg break that knot. */
nav { background: var(--nav-bg); padding: 0 1.5rem; }
.nav-inner {
  max-width: var(--nav-max); margin: 0 auto;
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 0.5rem; padding: 0.75rem 0;
}
.nav-brand {
  color: var(--nav-fg); text-decoration: none; font-size: var(--wordmark-size);
  letter-spacing: var(--wordmark-track); margin-right: auto; white-space: nowrap;
}
nav ul {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.25rem 1.5rem;
}
nav ul a {
  color: var(--nav-dim); text-decoration: none; font-size: 0.9rem;
  letter-spacing: var(--nav-track); transition: color 0.15s;
}
nav ul a:hover, nav ul a.active { color: var(--nav-fg); }
nav ul a.cta-link { color: var(--nav-cta); }
nav ul a.cta-link:hover { color: var(--nav-fg); }

/* ── Page header ─────────────────────────────────────────── */
.page-header {
  text-align: center; padding: 3.5rem 1.5rem 2.5rem;
  border-bottom: 1px solid var(--rule);
}
.page-header h1 { font-size: clamp(1.8rem, 4vw, 2.8rem); margin: 0 0 0.5rem; color: var(--ink); }
.page-header .subtitle { color: var(--sea); font-style: italic; margin: 0; font-size: 1.1rem; }

/* ── Buttons ─────────────────────────────────────────────── */
/* Hover is filter: brightness(), never a second hardcoded colour. The old Bondi
   pair (#a83f1f / #245a73) was a hand-picked darkening of ONE palette and is
   silently wrong under any other — the same defect class as the hardcoded #444.
   --accent-fg exists because an amber accent needs DARK text on it: a contrast
   fix, not a preference. */
.btn {
  display: inline-block; text-decoration: none; padding: 0.85rem 2rem;
  border-radius: 4px; font-weight: bold; font-size: 1.05rem; transition: filter 0.15s;
  font-family: var(--label); letter-spacing: var(--label-track);
}
.btn-primary { background: var(--accent); color: var(--accent-fg); }
.btn-primary:hover { filter: brightness(0.9); }
.btn-secondary { background: var(--sea); color: var(--sea-fg); }
.btn-secondary:hover { filter: brightness(0.9); }

/* ── Main content wrapper ────────────────────────────────── */
main { max-width: var(--content-max); margin: 0 auto; padding: 3rem 1.5rem 5rem; }
main.narrow { max-width: 720px; }

/* ── Section spacing ─────────────────────────────────────── */
section { margin-bottom: 3.5rem; }
section h2 {
  font-size: 1.5rem; color: var(--sea); margin: 0 0 0.75rem;
  padding-bottom: 0.4rem; border-bottom: 1px solid var(--rule);
}

/* ── Series card (hub + worlds) ──────────────────────────── */
.series-card {
  background: var(--paper); border: 1px solid var(--rule); border-radius: 6px;
  overflow: hidden; display: flex; gap: 1.5rem; padding: 1.5rem;
  text-decoration: none; color: inherit; transition: box-shadow 0.15s;
  margin-bottom: var(--series-card-gap);
}
.series-card:hover { box-shadow: var(--shadow-hover); }
.series-card img { width: 120px; flex-shrink: 0; object-fit: cover; border-radius: 3px; }
.series-card-body h3 { margin: 0 0 0.3rem; font-size: 1.3rem; color: var(--ink); }
.series-card-body .series-sub {
  font-family: var(--label); color: var(--rope); font-style: italic;
  margin: 0 0 0.75rem; font-size: 0.95rem;
}
.series-card-body p { margin: 0 0 1rem; color: var(--body); font-size: 0.95rem; }

/* ⚠ UNSCOPED on purpose. This was only ever defined as `.series-card-body
   .card-link` and `.world-card .card-link`, so the class did nothing outside a
   card - and a hand-authored page using it got the BROWSER default, which turns
   purple once visited. Caught on the two new brands' home pages, where the
   "Enter The Knowledge/Black" links rendered as underlined purple against the
   palette. A class named .card-link should mean the same thing wherever it is
   written; the two scoped rules below are now redundant but harmless. */
.card-link {
  color: var(--sea); font-weight: bold; font-size: 0.95rem; text-decoration: none;
}
.card-link:hover { text-decoration: underline; }
.series-card-body .card-link { color: var(--sea); font-weight: bold; font-size: 0.95rem; }

/* ── Books grid (series page) ────────────────────────────── */
.books-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 2rem; }
.book-card { background: var(--paper); border: 1px solid var(--rule); border-radius: 6px; overflow: hidden; }
.book-card img {
  width: 100%; display: block; aspect-ratio: 2/3; object-fit: cover;
  background: var(--cover-fallback);
}
.book-card-body { padding: 1rem 1.25rem 1.25rem; }
.book-card-body .book-num {
  font-family: var(--label); color: var(--rope);
  font-size: 0.85rem; font-weight: bold; margin: 0 0 0.2rem;
}
.book-card-body h3 { font-size: 1.1rem; margin: 0 0 0.75rem; }
.book-card-body .blurb { font-size: 0.9rem; color: var(--body); line-height: 1.55; margin: 0 0 1rem; }
.book-card-body .status { font-size: 0.85rem; color: var(--muted); font-style: italic; }
.book-card-body .status.free { color: var(--sea); font-style: normal; font-weight: bold; }

/* A magnet is an ordinary book SOLD at a price; giving it to the list is a
   separate, occasional route, not a price (ruled 2026-08-29). These mark the
   route beside the ordinary buy row. */
.badge-free {
  display: inline-block; background: var(--sea); color: var(--sea-fg);
  font-family: var(--label); font-size: 0.7rem; font-weight: bold;
  letter-spacing: .06em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 3px; vertical-align: middle; margin-right: 0.4em;
}
.book-card--free { border-color: var(--sea); }
.series-card--free { border-left: 3px solid var(--sea); }

/* ── Per-book buy/read links ─────────────────────────────── */
.book-links { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem; }
.btn-small {
  display: inline-block; text-decoration: none; padding: 0.4rem 1rem;
  border-radius: 4px; font-size: 0.85rem; font-weight: bold;
  font-family: var(--label); letter-spacing: var(--label-track-sm);
  background: var(--accent); color: var(--accent-fg); transition: filter 0.15s;
}
.btn-small:hover { filter: brightness(0.9); }
.btn-small.alt { background: var(--sea); color: var(--sea-fg); }

/* ── CTA box ─────────────────────────────────────────────── */
.cta-box {
  background: var(--paper); border: 1px solid var(--rule); border-radius: 6px;
  padding: 2.5rem 2rem; text-align: center; margin: 3rem 0;
}
.cta-box h2 { border: none; color: var(--ink); font-size: 1.5rem; margin: 0 0 0.5rem; }
.cta-box p { color: var(--muted); margin: 0 0 1.5rem; }

/* ── World intro ─────────────────────────────────────────── */
.world-intro p { font-size: 1.05rem; max-width: 680px; }

/* ── Footer ──────────────────────────────────────────────── */
footer {
  text-align: center; padding: 2rem 1.5rem; color: var(--muted);
  font-size: 0.88rem; border-top: 1px solid var(--rule);
}
footer a { color: var(--sea); text-decoration: none; }
footer a:hover { text-decoration: underline; }

/* ── Responsive ──────────────────────────────────────────── */
@media (max-width: 600px) {
  .series-card { flex-direction: column; }
  .series-card img { width: 100%; height: var(--series-card-img-h-sm); }
  .books-grid { grid-template-columns: 1fr; }
  .nav-brand { font-size: 0.95rem; }
}

/* placeholder for books without cover art yet */
.cover-placeholder { background: var(--placeholder-bg); border-radius: 4px; min-height: 180px; width: 100%; }

/* parts/singleworld.css — components only the singleworld LAYOUT renders.
   One canonical /world/ page per brand (plus /world/<slug>/ for any additional
   universe the brand carries), an R1413 image manifest placing photo furniture,
   and the free-marketing-material download row.

   ⚠ The download row is the THIRD give-away channel and must not be collapsed
   into the other two: a book that is SOLD, a book given to the list, and
   marketing material free to everyone. Only this last one lives here. */

/* ── Download row (free marketing PDFs) ─────────────────── */
.download-row {
  display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem 1.25rem;
  background: var(--paper); border: 1px solid var(--rule); border-radius: 6px;
  padding: 1.25rem 1.5rem; margin: 1.5rem 0;
}
.download-row .dl-text { flex: 1; min-width: 220px; }
.download-row .dl-text strong { display: block; font-size: 1.05rem; }
.download-row .dl-text span { color: var(--muted); font-size: 0.9rem; }

/* ── Book card: POV character line ───────────────────────── */
.book-card-body .character {
  font-family: var(--label); font-size: 0.85rem; color: var(--rope);
  font-style: italic; margin: 0 0 0.85rem;
}

/* ── Illustration banner (world page) ────────────────────── */
.illustration-banner {
  width: 100%; border-radius: 6px;
  box-shadow: 0 3px 14px rgba(0,0,0,0.15);
  display: block; margin: 0 0 2.5rem;
}

/* ── Scattered photos (manifest-placed) ──────────────────── */
.photo-scatter {
  position: relative; height: 380px; max-width: 900px;
  margin: 0 auto 1rem; pointer-events: none;
}
.photo-scatter .snap {
  position: absolute; box-shadow: 3px 6px 22px rgba(0,0,0,0.22);
  max-height: 300px; width: auto;
}
.photo-scatter .snap:nth-child(1) { width: 270px; left: 2%;  top: 55px; transform: rotate(-5deg);  z-index: 1; }
.photo-scatter .snap:nth-child(2) { width: 420px; left: 22%; top: 15px; transform: rotate(2.5deg); z-index: 3; }
.photo-scatter .snap:nth-child(3) { width: 360px; right: 1%; top: 65px; transform: rotate(-2deg);  z-index: 2; }
/* Series page — 2-photo scatter */
.photo-scatter.two-up { height: 440px; }
.photo-scatter.two-up .snap:nth-child(1) { width: 520px; left: 3%;  top: 25px; transform: rotate(-3deg);  z-index: 1; }
.photo-scatter.two-up .snap:nth-child(2) { width: 480px; right: 2%; top: 55px; transform: rotate(3.5deg); z-index: 2; }

/* ── Featured standalone photo ───────────────────────────── */
.photo-feature {
  display: block; margin: 2.5rem auto; max-width: 700px; width: 100%;
  box-shadow: 4px 7px 24px rgba(0,0,0,0.2);
}
.photo-feature.tilt-left  { transform: rotate(-2deg); }
.photo-feature.tilt-right { transform: rotate(2deg); }
/* Portrait postcard — constrained narrower so it doesn't dominate */
.photo-feature.postcard { max-width: 430px; }
.photo-feature.postcard.tilt-left  { transform: rotate(-1.5deg); }
.photo-feature.postcard.tilt-right { transform: rotate(1.5deg); }

@media (max-width: 600px) {
  .photo-scatter {
    height: auto; display: flex; flex-direction: column;
    align-items: center; gap: 1.5rem; padding: 1rem 0 2rem;
  }
  .photo-scatter .snap,
  .photo-scatter.two-up .snap {
    position: static; width: 88%; max-width: 360px; max-height: none;
  }
  .photo-scatter .snap:nth-child(odd)  { transform: rotate(-2deg); }
  .photo-scatter .snap:nth-child(even) { transform: rotate(2deg); }
}

/* parts/home-davidnairnbooks.css — hero + cinema for davidnairnbooks.com's
   HAND-AUTHORED pages (home, about, newsletter, privacy). The generator never
   writes those pages; it does write the stylesheet they load, so their CSS
   lives here.

   ART DIRECTION, per BRAND. The four frames came across from johnnairn-website
   with the universe under R2900 P7; they were rendered for The Black.

   theblack sits on a DARK ground, so this takes a scrim like johnnairn's rather
   than leslienairn's paper wash. The cut is the fastest of the four sites -
   16s over four frames, a harder push-in - because this is the one universe
   where something is always about to go wrong. Restraint still applies: no
   chrome, no flare, one amber signal. */

/* ── Hero (static fallback; the home page wraps it in .cinema-hero) ────────── */
.hero {
  text-align: center;
  padding: 5.5rem 1.5rem 4rem;
  border-bottom: 1px solid var(--rule);
  background:
    radial-gradient(70% 100% at 72% 8%, color-mix(in srgb, var(--sea) 16%, transparent) 0%, transparent 62%),
    linear-gradient(185deg, var(--paper) 0%, var(--sand) 78%);
}
.hero h1 { font-size: clamp(2.4rem, 6vw, 4rem); margin: 0 0 0.4rem; color: var(--ink); }
.hero .tagline { color: var(--nav-cta); font-style: italic; font-size: 1.25rem; margin: 0 0 2rem; }
.hero .lead { max-width: 620px; margin: 0 auto 2.5rem; font-size: 1.12rem; color: var(--body); }

/* ── Cinema hero — cross-fading stills. Pure CSS. ────────────────────────── */
.cinema { position: relative; overflow: hidden; border-bottom: 1px solid var(--rule); }
.cinema-frames { position: absolute; inset: 0; z-index: 0; }
.cinema .frame {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  opacity: 0; will-change: opacity, transform;
  animation: dnCinemaFade 16s infinite, dnCinemaKB 16s infinite;
}
.cinema .frame:nth-child(1) { animation-delay: 0s; }
.cinema .frame:nth-child(2) { animation-delay: 4s; }
.cinema .frame:nth-child(3) { animation-delay: 8s; }
.cinema .frame:nth-child(4) { animation-delay: 12s; }
@keyframes dnCinemaFade {
  0% { opacity: 0; } 3% { opacity: 1; } 21% { opacity: 1; } 25% { opacity: 0; } 100% { opacity: 0; }
}
@keyframes dnCinemaKB {
  0% { transform: scale(1.05); } 25% { transform: scale(1.15); } 100% { transform: scale(1.15); }
}
.cinema-caps { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.cinema-caps span {
  position: absolute; left: 1.5rem; right: 1.5rem; bottom: 1.1rem; text-align: center;
  font-family: 'Lora', Georgia, serif; font-style: italic; font-size: 1.05rem; color: var(--ink);
  text-shadow: 0 1px 10px rgba(0,0,0,0.9), 0 0 4px rgba(0,0,0,0.9);
  opacity: 0; animation: dnCinemaFade 16s infinite;
}
.cinema-caps span:nth-child(1) { animation-delay: 0s; }
.cinema-caps span:nth-child(2) { animation-delay: 4s; }
.cinema-caps span:nth-child(3) { animation-delay: 8s; }
.cinema-caps span:nth-child(4) { animation-delay: 12s; }
/* Dark scrim, darkening toward the text band, with a centre glow so the heading
   stays legible over a busy frame. */
.cinema-hero {
  position: relative; z-index: 2; border-bottom: none;
  background:
    radial-gradient(120% 90% at 50% 45%, rgba(7,10,13,0.20) 0%, rgba(7,10,13,0.62) 100%),
    linear-gradient(rgba(7,10,13,0.24), rgba(7,10,13,0.58));
}
.cinema-hero h1, .cinema-hero .tagline, .cinema-hero .lead {
  text-shadow: 0 2px 14px rgba(0,0,0,0.85), 0 0 6px rgba(0,0,0,0.7);
}

@media (prefers-reduced-motion: reduce) {
  /* Keep the opacity cross-fade (fades are vestibular-safe), drop the zoom. */
  .cinema .frame { animation: dnCinemaFade 16s infinite; transform: none; }
  .cinema-caps span { animation: dnCinemaFade 16s infinite; }
}

/* Three-up teaser row on the home page. */
.universe-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 2rem; align-items: start;
}
