/* Design pass (see docs/PLAN.md section 5/8): mobile-first, relative
   units, visible focus meeting WCAG 2.2 non-text contrast (3:1), no
   table-based layout, a verified AA/AAA-contrast palette (checked with a
   contrast calculation, not by eye - see the design-pass notes in
   docs/PLAN.md), a working mobile nav (replacing the legacy's hover-only
   dropdown), and a dark-mode variant via prefers-color-scheme. */

:root {
  --color-ink: #1a2630;
  --color-paper: #fdfaf0;
  --color-surface: #ffffff;
  --color-navy: #1f4f63;
  --color-navy-dark: #163a49;
  --color-cream: #e7e495;
  --color-border: #d8d3b8;
  --color-meta: #555555;
  --color-focus: #9c3d00; /* 6.5:1 on --color-paper, 6.8:1 on white - meets WCAG 2.2 non-text contrast */
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-heading: Georgia, "Times New Roman", serif;
  --radius: 0.5rem;
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 1rem;
  --space-4: 1.5rem;
  --space-5: 2.5rem;
  --space-6: 4rem;
}

/* Dark mode applies automatically from the visitor's own OS/browser
   preference (prefers-color-scheme), same as before - but a visitor
   can now also override that with the header's light/dark toggle
   (see templates/partials/theme-toggle.php, assets/js/theme-init.js
   and site.js), which sets data-theme="light"/"dark" on <html> and
   remembers the choice in localStorage. The :not([data-theme="light"])
   guard on the media-query block stops an explicit "light" choice
   being overridden by a dark OS preference; the plain
   :root[data-theme="dark"] block below handles the opposite case (dark
   explicitly chosen on a light-preferring OS) - see docs/PLAN.md
   section 7bg. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --color-ink: #e9ecef;
    --color-paper: #16202a;
    --color-surface: #1e2b38;
    --color-navy: #4f9cc0;
    --color-navy-dark: #0f1922;
    --color-cream: #4a4620;
    --color-border: #37444f;
    --color-meta: #aab4bd;
    --color-focus: #ffb366;
  }
  :root:not([data-theme="light"]) .card img, :root:not([data-theme="light"]) .otd-card img { background: var(--color-border); }
}
:root[data-theme="dark"] {
  --color-ink: #e9ecef;
  --color-paper: #16202a;
  --color-surface: #1e2b38;
  --color-navy: #4f9cc0;
  --color-navy-dark: #0f1922;
  --color-cream: #4a4620;
  --color-border: #37444f;
  --color-meta: #aab4bd;
  --color-focus: #ffb366;
}
:root[data-theme="dark"] .card img, :root[data-theme="dark"] .otd-card img { background: var(--color-border); }

* { box-sizing: border-box; }

/* Accessibility baseline: the site's own visitors are mostly in their
   70s (owner feedback), so defaults lean toward larger, clearer text and
   bigger touch targets rather than a typical "modern web app" density -
   112.5% makes the base size ~18px instead of the usual 16px. Everything
   below is in rem, so it scales with this and with the visitor's own
   browser zoom/text-size settings either way. */
html { font-size: 112.5%; }

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--color-ink);
  background: var(--color-paper);
  line-height: 1.65;
  font-size: 1.05rem;
}

img { max-width: 100%; }

/* Larger minimum touch targets for discrete controls - buttons, form
   fields, nav items (WCAG 2.5.8 exempts links that sit inline within a
   sentence of running text from a minimum size, which is most of the
   links on plane/artist/book pages - enlarging those would do more harm
   than good to readability, so this targets controls, not body text). */
button, input, select, textarea, .nav-toggle { min-height: 2.75rem; }
input[type="checkbox"], input[type="radio"] { min-height: 1.5rem; width: 1.5rem; height: 1.5rem; }
#main-nav a, .site-footer nav a { display: inline-block; padding: var(--space-1) 0; }

.wrap { max-width: 72rem; margin: 0 auto; padding: 0 1rem; }

.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
}
.skip-link:focus {
  left: 0.5rem;
  top: 0.5rem;
  background: var(--color-surface);
  padding: 0.5rem 1rem;
  z-index: 100;
  border-radius: var(--radius);
}

a { color: var(--color-navy); }
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}

h1, h2, h3 { font-family: var(--font-heading); line-height: 1.2; }
h1 { font-size: clamp(1.75rem, 4vw, 2.5rem); margin-top: 0; }
h2 { font-size: clamp(1.3rem, 3vw, 1.75rem); }

/* --- Header / navigation --- */
/* Single navy bar carrying the project's own badge (kept as-is, just
   recoloured white-on-transparent from the original black-on-white GIF -
   not ours to redesign, see docs/PLAN.md section 5 and 7e) plus the site
   name and nav. The legacy site used a separate full-width white banner
   row for its wide logo above the nav; the owner found that jarring
   against the new navy header, so the compact badge sits inline instead. */
.site-nav-bar {
  background: var(--color-navy);
  color: #fff;
}
.site-nav-bar .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) 1rem;
}
.site-header .brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: #fff;
  text-decoration: none;
  font-family: var(--font-heading);
  font-size: 1.15rem;
  font-weight: bold;
}

.nav-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-3);
  background: transparent;
  border: 1px solid rgba(255,255,255,0.6);
  border-radius: var(--radius);
  color: #fff;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.nav-toggle-bars, .nav-toggle-bars::before, .nav-toggle-bars::after {
  display: block;
  width: 1.25rem;
  height: 2px;
  background: #fff;
  position: relative;
}
.nav-toggle-bars::before { content: ""; position: absolute; top: -6px; }
.nav-toggle-bars::after { content: ""; position: absolute; top: 6px; }

/* Light/dark toggle - sits in the nav bar, always visible (not inside
   the collapsible mobile nav, so it's reachable without opening the
   menu). The two label spans are swapped by data-theme/prefers-color-
   scheme alone, in plain CSS, matching the same selector pattern as
   the theme variables above - no JS needed just to show the right
   label on first paint. See docs/PLAN.md section 7bg. */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-3);
  background: transparent;
  border: 1px solid rgba(255,255,255,0.6);
  border-radius: var(--radius);
  color: #fff;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.theme-toggle-to-light { display: none; }
:root[data-theme="dark"] .theme-toggle-to-dark { display: none; }
:root[data-theme="dark"] .theme-toggle-to-light { display: inline; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle-to-dark { display: none; }
  :root:not([data-theme="light"]) .theme-toggle-to-light { display: inline; }
}

#main-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  list-style: none;
  margin: 0;
  padding: 0;
}
#main-nav a { color: #fff; text-decoration: none; }
#main-nav a:hover, #main-nav a:focus { text-decoration: underline; }

@media (max-width: 47.99rem) {
  .nav-toggle { display: inline-flex; }
  #main-nav {
    display: none;
    width: 100%;
    order: 3;
  }
  #main-nav.is-open { display: block; }
  #main-nav ul { flex-direction: column; gap: var(--space-2); padding: var(--space-3) 0; }
}
@media (min-width: 48rem) {
  .nav-toggle { display: none; }
}

/* #main also carries .wrap (max-width/margin/horizontal padding) - this
   rule must win the vertical padding, so it needs to match .wrap's
   specificity (a bare `main` element selector loses to `.wrap`'s class
   selector and silently gets overridden to padding:0, which is exactly
   what caused the hero section below to overlap the header - its
   negative margin had no padding left to cancel against). */
main.wrap { padding-top: var(--space-4); padding-bottom: var(--space-6); min-height: 50vh; }

/* --- Hero (home page) --- */
.hero {
  background: linear-gradient(135deg, var(--color-navy) 0%, var(--color-navy-dark) 100%);
  color: #fff;
  margin: calc(var(--space-4) * -1) -1rem var(--space-5);
  padding: var(--space-5) 1rem;
}
.hero .wrap { max-width: 72rem; margin: 0 auto; padding: 0; }
.hero h1 { color: #fff; margin-bottom: var(--space-2); }
.hero .lede { color: #e8eef1; }
.hero .button { margin-top: var(--space-3); }

.lede { font-size: 1.1rem; max-width: 42rem; }

.stat-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  list-style: none;
  padding: 0;
  margin: var(--space-4) 0;
}
.stat-row strong { font-size: 1.5rem; display: block; color: var(--color-navy); }
.hero .stat-row strong { color: #fff; }
.stat-row-note { font-size: 0.85rem; margin: calc(var(--space-4) * -1) 0 var(--space-3); }
.hero .stat-row-note { color: #e8eef1; }

.button {
  display: inline-block;
  background: var(--color-navy);
  color: #fff;
  padding: 0.65rem 1.3rem;
  border-radius: var(--radius);
  text-decoration: none;
  border: none;
  font: inherit;
  cursor: pointer;
  transition: transform 0.1s ease, background-color 0.15s ease;
}
.button:hover { background: var(--color-navy-dark); }
.button:active { transform: translateY(1px); }

/* A quiet secondary call-to-action (e.g. "report an error on this
   page") - a bordered box rather than the loud solid .button, since
   this is a low-priority, always-present link, not a primary action.
   A fixed pill radius looked odd once the text wraps to 2-3 lines in
   a narrow sidebar column, so this uses the site's standard --radius
   instead. inline-flex + gap keeps the arrow glued to "know" instead
   of wrapping onto its own line the way a plain <a> did before. */
.report-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: var(--space-3) 0;
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  color: var(--color-meta);
  text-decoration: none;
  font-size: 0.9rem;
  line-height: 1.35;
  transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
}
.report-link:hover { border-color: var(--color-navy); color: var(--color-navy); background: var(--color-surface); }
.report-link-arrow { flex-shrink: 0; }

.notice {
  background: var(--color-cream);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 0.75rem 1rem;
  margin: 1rem 0;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: var(--space-3);
  margin: var(--space-4) 0;
}
.card {
  display: block;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  background: var(--color-surface);
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.card:hover, .card:focus-visible { box-shadow: 0 0.5rem 1.25rem rgba(0,0,0,0.12); transform: translateY(-2px); }

/* Unified click-to-enlarge cursor, matching the hero image's zoom-in
   affordance - see site.js's lightbox-gallery handling. */
.lightbox-gallery a, .lightbox-gallery a img { cursor: zoom-in; }

/* Leaflet map containers (units/missions/plane-journey maps) - height
   has to come from a stylesheet rule, not a style="" attribute on the
   element, since the CSP has no unsafe-inline for style-src. */
.geo-map { height: 65vh; min-height: 22rem; margin: var(--space-3) 0; border-radius: var(--radius); overflow: hidden; }
.geo-map-small { height: 20rem; min-height: 16rem; }
/* Coloured dot markers (point-map.js's "color" option) - a confirmed
   loss site vs. a less precise last-known position on the same map,
   distinct from the default blue pin used for everything else. */
.geo-marker-dot { width: 18px; height: 18px; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 3px rgba(0, 0, 0, 0.6); }
.geo-marker-dot-orange { background: #ea580c; }
.geo-marker-dot-red { background: #dc2626; }
.geo-marker-dot-purple { background: #7c3aed; }
.geo-marker-dot-grey { background: #6b7280; }
.geo-marker-dot-teal { background: #0d9488; }
.geo-map-legend { display: flex; gap: var(--space-3); flex-wrap: wrap; font-size: 0.85rem; color: var(--color-meta); margin: 0 0 var(--space-2); }
.geo-map-legend-dot { display: inline-block; width: 0.7rem; height: 0.7rem; border-radius: 50%; margin-right: 0.3rem; vertical-align: middle; }
.geo-map-legend-dot-orange { background: #ea580c; }
.geo-map-legend-dot-red { background: #dc2626; }
.geo-map-legend-dot-blue { background: #2a81cb; }
.geo-map-legend-dot-purple { background: #7c3aed; }
.geo-map-legend-dot-grey { background: #6b7280; }
.geo-map-legend-dot-teal { background: #0d9488; }
/* Label/value pairs (plane fate record, etc.) */
.meta-list { display: grid; grid-template-columns: auto 1fr; gap: 0.25rem 0.75rem; margin: 0; }
.meta-list dt { font-weight: 600; color: var(--color-meta); }
.meta-list dd { margin: 0; }

/* A plane's own at-a-glance service timeline (first mission on record
   -> N missions flown -> fate) - see docs/PLAN.md section 7as. Dot
   colours reuse the same red/teal/grey/blue language as the map
   markers and status badges (sections 7ak/7ar) - red = lost, teal =
   survived the war (a postwar disposal site), grey = a neutral/
   unknown-outcome stat or milestone, blue = the plane's first known
   mission. Horizontal with a connecting line on a wide screen; a
   plain top-to-bottom list on narrow ones, since there's no room to
   lay three columns out side by side there. */
.mini-timeline { display: flex; list-style: none; margin: var(--space-3) 0 var(--space-4); padding: 0; }
.mini-timeline-item { position: relative; flex: 1; text-align: center; padding: var(--space-4) var(--space-2) 0; min-width: 0; }
.mini-timeline-item:not(:first-child)::before {
  content: ''; position: absolute; top: 0.5rem; left: -50%; width: 100%; height: 2px;
  background: var(--color-border); z-index: 0;
}
.mini-timeline-dot {
  position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: 1rem; height: 1rem; border-radius: 50%; border: 2px solid var(--color-surface); z-index: 1;
}
.mini-timeline-dot-blue { background: #2a81cb; }
.mini-timeline-dot-red { background: #dc2626; }
.mini-timeline-dot-teal { background: #0d9488; }
.mini-timeline-dot-grey { background: #6b7280; }
.mini-timeline-label { display: block; font-weight: 600; font-size: 0.9rem; }
.mini-timeline-date, .mini-timeline-detail { display: block; color: var(--color-meta); font-size: 0.8rem; }
.mini-timeline-detail { font-style: italic; }
@media (max-width: 47.99rem) {
  .mini-timeline { flex-direction: column; align-items: stretch; gap: var(--space-3); }
  .mini-timeline-item { text-align: left; padding: 0 0 0 var(--space-4); }
  .mini-timeline-item:not(:first-child)::before { top: -0.65rem; left: 0.4rem; width: 2px; height: 0.65rem; }
  .mini-timeline-dot { top: 0.1rem; left: 0; transform: none; }
}
.card img { width: 100%; height: 9rem; object-fit: cover; display: block; background: var(--color-border); }
.card h2, .card h3 { font-size: 1rem; margin: 0.5rem 0.75rem 0; }
.card .meta { margin: 0.25rem 0.75rem 0.75rem; font-size: 0.85rem; color: var(--color-meta); }

.breadcrumb { font-size: 0.9rem; margin-bottom: var(--space-3); }

.hero-img { max-width: 100%; border-radius: var(--radius); margin: var(--space-3) 0; }

.meta { color: var(--color-meta); }

.pagination {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: var(--space-5) 0;
}

.status-badge {
  display: inline-block;
  padding: 0.25rem 0.75rem;
  border-radius: 999px;
  font-size: 0.85rem;
  background: var(--color-border);
}
/* A sortie this specific aircraft aborted/was recalled from - a per-
   plane fact, see PLANE_MISSION.ABORTED and docs/PLAN.md section 7w.
   Same grey as the abort map marker (.geo-marker-dot-grey) - see
   docs/PLAN.md section 7ak for the tag/pin colour language overall. */
.status-badge-aborted { background: #6b7280; color: #fff; }
/* Credit status is known and positive ("still counted") - a distinct
   colour from the plain grey "aborted" badge (not credited, or not
   stated), same label either way - see docs/PLAN.md section 7ac. Same
   teal as the safe-diversion-landing map marker (.geo-marker-dot-teal):
   a credited abort and a safe landing are both "the crew is fine,
   sortie counted" outcomes - see section 7ak. */
.status-badge-aborted-credited { background: #0d9488; color: #fff; }
/* Deliberately NOT red - that colour is reserved for a genuine loss
   (.status-badge-lost, crash/confirmed-loss map markers) - a scrubbed
   mission is the mildest outcome here (nothing even took off), so it
   gets its own neutral slate rather than reading as a danger colour.
   See docs/PLAN.md section 7ak. */
.status-badge-scrubbed { background: #475569; color: #fff; }
/* This specific aircraft did not return from this sortie (MIA/KIA/
   shot down - see SortieNotesAnalyzer::statusBadge()'s $lost param).
   Same red as a crash-landing/confirmed-loss map marker
   (.geo-marker-dot-red) - see docs/PLAN.md section 7ak. */
.status-badge-lost { background: #dc2626; color: #fff; }
/* This aircraft never actually got airborne as part of the mission
   ("failed to take off", a ground spare not needed) - distinct from a
   plain Aborted (which took off and turned back). A cooler, bluer
   slate than both Scrubbed's neutral grey-slate (#475569) and Aborted's
   plain grey (#6b7280), since all three are easy to conflate as
   "nothing really happened" outcomes but are different facts - see
   docs/PLAN.md section 7ax. */
.status-badge-no-sortie { background: #64748b; color: #fff; }
/* Admin mission list row tints - see docs/PLAN.md section 7x. */
.mission-row-scrubbed { background: rgba(153, 27, 27, 0.12); }
.mission-row-aborted { background: rgba(107, 114, 128, 0.12); }

/* A plain data table - originally admin-only (.admin-table lived in
   admin.css), but several public pages (a mission's roster, a plane's
   known-mission list, pilot/lost-aircraft lists) use the exact same
   class and were rendering completely unstyled, since admin.css only
   loads on /admin/* pages - see docs/PLAN.md section 7w. */
.admin-table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
.admin-table th, .admin-table td { text-align: left; padding: 0.5rem; border-bottom: 1px solid var(--color-border); }
/* The one row on a mission's roster matching ?plane=<shortname> (see
   templates/missions/show.php) - "this is the row about the plane you
   came from". */
.mission-roster-focus { background: var(--color-surface-alt, rgba(42, 129, 203, 0.12)); }
.status-in_print { background: #cfe8cf; color: #1a2630; }
.status-coming_soon { background: var(--color-cream); color: #1a2630; }

.buy-links { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 0.75rem; margin: 1rem 0; }

.book-images { display: flex; flex-wrap: wrap; gap: var(--space-3); margin: var(--space-4) 0; }
.book-images img { max-width: 18rem; border: 1px solid var(--color-border); border-radius: var(--radius); }

.site-footer {
  background: var(--color-navy-dark);
  color: #cfe3ea;
  padding: var(--space-4) 0;
  font-size: 0.9rem;
}
.site-footer a { color: #fff; }
.site-footer nav ul { list-style: none; display: flex; flex-wrap: wrap; gap: var(--space-3); padding: 0; margin: 0 0 var(--space-2); }

.text-center { text-align: center; }

.book-thumb-inline { vertical-align: middle; }

.home-intro { max-width: 48rem; }
.home-intro p { margin: 0 0 var(--space-3); }

.today-row { display: grid; grid-template-columns: 1fr; gap: var(--space-3); margin: var(--space-4) 0; }
.today-row h2 { margin-top: 0; }
@media (min-width: 48rem) {
  .today-row { grid-template-columns: 1fr 1fr; }
}

/* Shared form styling (used by every form on the site, not just admin -
   the class name is a holdover from being admin-only originally; see
   docs/PLAN.md section 7d). */
.flash { padding: 0.75rem 1rem; border-radius: var(--radius); margin: 1rem 0; }
.flash-success { background: #dff0d8; border: 1px solid #b8dba8; color: #1a2630; }
.flash-error { background: #f8d7da; border: 1px solid #e3a7ac; color: #1a2630; }

.admin-form { display: flex; flex-direction: column; gap: 0.35rem; max-width: 36rem; margin: 1rem 0; }
.admin-form label { font-weight: 600; margin-top: 0.5rem; }
.admin-form input, .admin-form select, .admin-form textarea {
  padding: 0.5rem; border: 1px solid var(--color-border); border-radius: var(--radius); font: inherit;
  background: var(--color-surface); color: var(--color-ink); width: 100%;
}
.admin-form .field-row { display: flex; gap: 1rem; flex-wrap: wrap; }
.admin-form .field-row > div { flex: 1; min-width: 8rem; }
.admin-form button { align-self: flex-start; margin-top: 1rem; }
.admin-form-inline { max-width: 100%; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.honeypot { position: absolute; left: -9999px; top: -9999px; }

.plain-list { list-style: none; padding: 0; }
.plain-list li { padding: 0.4rem 0; border-bottom: 1px solid var(--color-border); }

.unit-group { margin: var(--space-4) 0; }
.unit-list { list-style: none; padding: 0; }
.unit-list li { padding: 0.3rem 0; }

.otd-card { display: flex; gap: var(--space-3); align-items: flex-start; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius); padding: var(--space-3); margin: var(--space-3) 0; }
.otd-card img { border-radius: var(--radius); flex-shrink: 0; object-fit: cover; }

form[role="search"] { display: flex; gap: var(--space-2); margin: var(--space-3) 0 var(--space-4); max-width: 30rem; }
form[role="search"] input { flex: 1; padding: 0.5rem; border: 1px solid var(--color-border); border-radius: var(--radius); background: var(--color-surface); color: var(--color-ink); }

.cookie-notice {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  background: var(--color-navy-dark);
  color: #fff;
  border-top: 3px solid var(--color-focus);
  padding: var(--space-3) 0;
  z-index: 50;
}
.cookie-notice-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.cookie-notice p { margin: 0; max-width: 45rem; }
.cookie-notice a { color: #fff; text-decoration: underline; }
.cookie-notice .button { flex-shrink: 0; }

/* --- Lightbox (src/assets/js/site.js attaches this to .hero-img) ---
   The dialog's own max-width used to be smaller than the page's main
   content column (.wrap, 72rem) - so an enlarged photo could never
   actually display any bigger than it already looked inline, making
   the "click to enlarge" affordance pointless for any photo with
   enough resolution to show more detail. Sized well past .wrap so
   there's real room to grow. */
.lightbox {
  border: none;
  border-radius: var(--radius);
  padding: var(--space-3);
  background: var(--color-surface);
  max-width: min(95vw, 90rem);
  max-height: 95vh;
}
.lightbox::backdrop { background: rgba(0,0,0,0.7); }
/* width:100% (not max-width) + object-fit:contain deliberately lets a
   small source photo scale UP to fill the dialog - plain max-width:100%
   never upscales a raster image past its own natural resolution, which
   is the enlarged-dialog fix above doing nothing for this site's many
   small/low-resolution scanned photos (some under 200px wide) - it
   would stay exactly as "tiny" as inline, just inside a bigger empty
   box. A soft/blurry enlargement of a tiny scan is still more useful
   than "stays pixel-for-pixel tiny with nowhere further to go". */
.lightbox img { display: block; width: 100%; height: 82vh; object-fit: contain; margin: 0 auto; }
.lightbox-close {
  display: block;
  margin: 0 0 var(--space-2) auto;
  background: var(--color-navy);
  color: #fff;
  border: none;
  border-radius: var(--radius);
  padding: 0.4rem 0.9rem;
  cursor: pointer;
}

/* In-page confirm dialog (replaces the native window.confirm() popup
   for every [data-confirm] button/link site-wide - see site.js and
   docs/PLAN.md section 7bi), same <dialog>/::backdrop pattern as
   .lightbox above. */
.confirm-dialog {
  border: none;
  border-radius: var(--radius);
  padding: var(--space-4);
  background: var(--color-surface);
  color: var(--color-ink);
  max-width: min(90vw, 28rem);
}
.confirm-dialog::backdrop { background: rgba(0,0,0,0.5); }
.confirm-dialog p { margin: 0 0 var(--space-4); font-size: 1.05rem; }
.confirm-dialog-actions { display: flex; justify-content: flex-end; gap: var(--space-2); }
.button-danger { background: #a4262c; color: #fff; }

.plane-appearance { margin-bottom: var(--space-4); }
.appearance-img { max-width: 100%; border: 1px solid var(--color-border); border-radius: var(--radius); background: #fff; }
.plane-photo .image-credit { font-style: italic; }
.plane-books { margin: var(--space-4) 0; }
.plane-books h2 { font-size: 1.1rem; }
.plane-books .plain-list { border: 1px solid var(--color-border); border-radius: var(--radius); padding: var(--space-2) var(--space-3); }
.plane-books .plain-list li a { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); text-align: center; }
.plane-text { clear: both; }

@media (min-width: 48rem) {
  .plane-detail {
    display: grid;
    grid-template-columns: 14rem 1fr 12rem;
    grid-template-areas: "appearance photo books" "text text text";
    gap: var(--space-5);
    align-items: start;
  }
  .plane-appearance { grid-area: appearance; margin-bottom: 0; }
  .plane-photo { grid-area: photo; }
  .plane-books { grid-area: books; margin: 0; }
  .plane-text { grid-area: text; }

  .book-detail { display: grid; grid-template-columns: 18rem 1fr; gap: var(--space-5); align-items: start; }
  .book-detail h1, .book-detail .subtitle, .book-detail .meta,
  .book-detail .status-badge, .book-detail .buy-links, .book-detail .book-description {
    grid-column: 2;
  }
  .book-detail .hero-img { grid-column: 1; grid-row: 1 / span 6; width: 100%; margin: 0; }
  .book-detail .book-images { grid-column: 1 / -1; }
}
