/* Mobile-first. Brand colours arrive as --accent/--ink/--paper CSS variables set inline by
   the layout template, per request, from res.locals.brand. */

/* =====================================================================
   Direction E fonts (2026-09-29, Phase 1)
   Self-hosted, Latin-subset WOFF2 — built by scripts/build-fonts.mjs from the OFL TTFs in
   packages/render/fonts/ (the server-side poster renderer's own copies) and committed under
   apps/web/src/public/fonts/. Filenames carry an 8-char content hash (see manifest.json in that
   directory) so a font change always ships under a new URL — no separate cache-busting needed for
   these files the way `?v=` handles CSS/JS. `/fonts/` is served by two stacked express.static
   mounts (see apps/web/src/app.ts): PUBLIC_DIR first (these hashed files), then the render
   package's own fontDir() as a fallback for the plain .ttf files packages/render still uses
   server-side for poster rasterisation (untouched by this change).

   Oswald = display/heading face (Direction E's condensed uppercase headings). Cormorant = body
   serif. SpaceMono = the mono "plate/label" voice used throughout Direction E's chrome and
   captions. Inter 400/700 = the existing UI/body sans, unchanged in role, just re-pointed at the
   new hashed, subsetted file instead of the old unsubsetted TTF.

   Each real face is paired with a "-fallback" face carrying size-adjust/ascent-override/
   descent-override metric overrides, computed from the actual 'head'/'hhea'/'OS/2' tables of the
   webfont and of a locally-installed stand-in for its fallback (Futura for Oswald — Avenir Next
   Condensed itself isn't installed on this build machine to measure directly; Georgia for
   Cormorant; Menlo for SpaceMono; formula per Google's web.dev font-fallback guidance / the
   `fontaine`/`next/font` implementations). This keeps the fallback's box metrics close to the
   real font's so text reflows only slightly, not doubling in size or shifting lines, during the
   font-display: swap window. Inter has no metric-fallback pair: its stack already falls back to
   -apple-system/BlinkMacSystemFont/system-ui, which are already close matches by design. */

@font-face {
  font-family: 'Oswald';
  src: url('/fonts/oswald-400.344c3aa0.woff2') format('woff2');
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Oswald-fallback';
  src: local('Avenir Next Condensed');
  size-adjust: 81.74%;
  ascent-override: 145.94%;
  descent-override: 35.35%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Cormorant';
  src: url('/fonts/cormorant-400.74280c95.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Cormorant-fallback';
  src: local('Georgia');
  size-adjust: 122.52%;
  ascent-override: 75.42%;
  descent-override: 23.43%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'SpaceMono';
  src: url('/fonts/spacemono-400.176aec69.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'SpaceMono-fallback';
  src: local('Menlo');
  size-adjust: 101.65%;
  ascent-override: 110.18%;
  descent-override: 35.51%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-400.51f1508d.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-700.5e7998aa.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ---------- Motion: one centralised reduced-motion rule for the whole site (semantics ported
   from design-explorations/direction-e/styles.css line 96) — scroll snaps instead of smooth-
   scrolling, every animation/transition collapses to effectively instant, transforms on parallax
   background layers are cancelled, and anything gated behind a scroll/intersection reveal is shown
   outright rather than staying invisible. Theme- and component-specific reduced-motion rules
   (theme-atlas.css, theme-nightfall.css, designer.css) layer additional semantics on top of this —
   e.g. swapping a spinner for a static state — but the blanket kill-switch lives here once. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

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

  .hero-field,
  .product-atmosphere {
    transform: none !important;
  }

  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* Neutral hairline/tint tokens, derived from the default --ink so borders and faint fills stay
   legible against whatever --paper a theme sets — see apps/web/src/public/css/theme-*.css, which
   redefine these (along with --accent/--ink/--paper) at `:root[data-theme=…]`. */
:root {
  --hairline: rgba(17, 24, 39, 0.08);
  --hairline-strong: rgba(17, 24, 39, 0.12);
  --gutter: 16px;
}

@media (min-width: 700px) {
  :root { --gutter: 32px; }
}

@media (min-width: 1280px) {
  :root { --gutter: 40px; }
}

* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-width: 0;
  overflow-x: hidden;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  color: var(--ink, #111827);
  background: var(--paper, #faf8f3);
  line-height: 1.5;
}

a {
  color: var(--accent, #1f3a5f);
}

.wrap {
  max-width: 960px;
  margin: 0 auto;
  padding: 0 16px;
}

/* Wider, gutter-aware container for the redesign-2026-09-28 chrome (header/footer, and any
   page that ports the shared/redesign.css component layer). Colourless — themes never need to
   override it. .wrap (above) stays for the older page bodies that still use it. */
.container {
  max-width: 1200px;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Screen-reader-only content (e.g. a <table>'s <caption> that repeats an adjacent visible
   heading) — visible to assistive tech, removed from the visual flow. */
.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* First focusable element on every page — off-screen until a keyboard user tabs to it, then
   pinned to the top so it's visible before the header/nav. Shared across both themes (unlike
   .visually-hidden's clip trick, this one needs to become visible again on :focus). */
.skip-link {
  position: absolute;
  top: -48px;
  left: 8px;
  z-index: 100;
  padding: 10px 16px;
  background: var(--ink, #111827);
  color: var(--paper, #faf8f3);
  text-decoration: none;
  border-radius: 4px;
  transition: top 0.15s ease;
}

.skip-link:focus {
  top: 8px;
}

.announcement {
  background: var(--accent, #1f3a5f);
  color: var(--paper, #faf8f3);
  text-align: center;
  padding: 8px 16px;
  font-size: 0.9rem;
}

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding: 20px 16px;
  border-bottom: 1px solid var(--hairline);
}

.wordmark {
  font-size: 1.25rem;
  font-weight: 700;
  text-decoration: none;
  color: var(--ink, #111827);
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.site-nav a {
  text-decoration: none;
  color: var(--ink, #111827);
  font-size: 0.95rem;
}

main {
  padding: 32px 16px 64px;
}

.btn {
  display: inline-block;
  padding: 12px 24px;
  /* 2px everywhere on this site, never a pill — both themes already override this to 2px at
     theme specificity; this default only matters on the untheme surfaces (admin). */
  border-radius: 2px;
  text-decoration: none;
  font-weight: 600;
  background: var(--accent, #1f3a5f);
  color: var(--paper, #faf8f3);
}

.btn-secondary {
  /* Self-sufficient: `.btn-secondary` must render as a full button on its own, not only when
     paired with `.btn` — a bare `<a class="btn-secondary">` (404.eta's "Design a star map",
     order.eta's downgraded Download link) was rendering as an underlined text link in a bordered
     box because only colours were declared here. Duplicates `.btn`'s layout declarations plus
     `min-height`/flex centring (`.btn` alone doesn't guarantee a 44px tap target at every font
     size) rather than depending on `.btn` also being present in markup. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 24px;
  border-radius: 2px;
  text-decoration: none;
  font-weight: 600;
  min-height: 44px;
  background: transparent;
  color: var(--accent, #1f3a5f);
  border: 1px solid var(--accent, #1f3a5f);
}

.content {
  max-width: 720px;
  margin: 0 auto;
}

.content h1 {
  font-size: 1.75rem;
}

.content h2 {
  font-size: 1.2rem;
  margin-top: 2em;
}

dt {
  font-weight: 600;
  margin-top: 1.25em;
}

dd {
  margin-left: 0;
  margin-top: 0.25em;
}

.site-footer {
  border-top: 1px solid var(--hairline);
  padding: 24px 16px 40px;
  font-size: 0.9rem;
}

/* Public-site footer copy (layout.eta's non-admin branch): a one-line description, a muted
   credits line, and the legal-name line under the links. Colourless here; themes set the colour
   that reads on their own footer background. */
.footer-line {
  font-size: 0.95rem;
  margin: 0 0 0.6rem;
  max-width: 60ch;
}

.footer-legal {
  font-size: 0.85rem;
  border-top: 1px solid var(--hairline);
  padding-top: 1.1rem;
  margin-top: 1.5rem;
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.4rem;
  margin: 1.25rem 0 0;
  padding: 0;
  list-style: none;
}

.footer-links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  text-decoration: none;
  font-size: 0.95rem;
}

.breadcrumbs {
  font-size: 0.85rem;
  color: var(--ink, #111827);
  opacity: 0.7;
  margin-bottom: 8px;
}

.breadcrumbs a {
  text-decoration: none;
}

.city-page {
  max-width: 900px;
}

.designer-page {
  max-width: 1100px;
}

.preview-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 16px;
  margin: 20px 0 28px;
}

.preview-card {
  display: block;
  text-decoration: none;
  color: inherit;
  text-align: center;
}

.preview-card img {
  width: 100%;
  height: auto;
  border-radius: 8px;
  border: 1px solid var(--hairline-strong);
  background: var(--hairline);
}

/* The home page's example strip is always exactly 6 images; a plain auto-fit grid wraps them
   5-then-1 at typical viewport widths, leaving one image stranded on its own row. */
.home-examples .preview-grid {
  grid-template-columns: repeat(3, 1fr);
}

@media (max-width: 600px) {
  .home-examples .preview-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

.preview-label {
  display: block;
  margin-top: 6px;
  font-size: 0.85rem;
  text-transform: capitalize;
}

.size-table {
  width: 100%;
  border-collapse: collapse;
  margin: 24px 0;
}

.size-table caption {
  text-align: left;
  font-weight: 600;
  margin-bottom: 8px;
}

.size-table th,
.size-table td {
  text-align: left;
  padding: 8px 12px;
  border-bottom: 1px solid var(--hairline);
}

.nearby-links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  list-style: none;
  padding: 0;
}

.country-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin: 16px 0 24px;
}

.country-list a,
.pagination a {
  text-decoration: none;
}

.country-list a.active,
.pagination a.active {
  font-weight: 700;
  text-decoration: underline;
}

.city-list {
  columns: 2;
  column-gap: 24px;
  padding: 0;
  list-style: none;
}

.city-list li {
  break-inside: avoid;
  margin-bottom: 6px;
}

.pagination {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin: 24px 0;
}

.card-link {
  display: block;
  margin-top: 10px;
  font-size: 0.9rem;
}

.home-examples,
.how-it-works,
.price-strip {
  max-width: 900px;
  margin: 40px auto;
  text-align: center;
}

.home-examples h2,
.how-it-works h2 {
  font-size: 1.4rem;
}

.steps {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
  margin-top: 20px;
  text-align: left;
}

.step {
  position: relative;
  padding-left: 44px;
}

.step-number {
  position: absolute;
  left: 0;
  top: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--accent, #1f3a5f);
  color: var(--paper, #faf8f3);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
}

.step h3 {
  margin: 0 0 4px;
  font-size: 1.05rem;
}

.step p {
  margin: 0;
}

.price-strip p {
  display: inline-block;
  margin: 4px 16px;
  font-size: 1rem;
}

.trust-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 24px;
  max-width: 960px;
  margin: 0 auto 24px;
  padding: 0;
  list-style: none;
  text-align: center;
  font-size: 0.85rem;
  opacity: 0.8;
}

.landing-page {
  max-width: 720px;
}

@media (min-width: 640px) {
  .site-nav {
    gap: 24px;
  }

  .steps {
    grid-template-columns: repeat(3, 1fr);
  }
}
