/* ========================================
   LANDING — Brief 18: England of schools (public/landing.css)
   Scoped to #screenWelcome + the topbar while body.on-welcome. Colours come from the
   Assembly tokens declared on .screen-welcome in style.css (--brand-green, --brand-orange,
   --land, --sea, --river) plus the DS greys (--ink, --ink-soft, --surface, --line).
   ======================================== */

/* ---- the screen: map behind, column in front ---- */
.screen-welcome {
  position: relative;
  height: 100vh;
  height: 100dvh;
  padding-top: 0;                 /* the map runs under the (transparent) topbar */
  overflow: hidden;
  background: var(--landing-ground, var(--land));
  color: var(--ink);
}
/* Brief 50 A2 / A3: the two landings, one set of names each (tokens.css holds every value). landing.js reads the map's
   colours off these, so the map, the fade and the text change together. Forest is the default; ?landing=light shows
   the other (landing.js sets data-landing before it reads a colour). */
.screen-welcome[data-landing="forest"] {
  --landing-ground: var(--forest);
  --landing-land: var(--forest-land);
  --landing-sea: var(--forest-sea);
  --landing-dot: var(--mint);
  --landing-headline: var(--surface);
  --landing-line: var(--forest-line);
  --landing-search-border: transparent;
  --landing-focus: var(--mint);
  --landing-lit-ring: var(--surface);   /* Linzie, 28 Oct: a white ring makes the orange matches stand out on the green */
}
.screen-welcome[data-landing="light"] {
  --landing-ground: var(--twin-ground);
  --landing-land: var(--surface);
  --landing-sea: var(--mist);
  --landing-dot: var(--forest);
  --landing-headline: var(--forest);
  --landing-line: var(--ink-soft);
  --landing-search-border: var(--orange);
  --landing-focus: var(--forest);
  --landing-lit-ring: var(--twin-ground);
}
/* A2: the ground's colour from the left edge, solid behind the column (it ends at 584 px), fading out by about 45 %
   of the width, over Ireland: the text sits on solid colour, never on the dots. */
.landing-fade {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(90deg, var(--landing-ground) 0, var(--landing-ground) 608px, transparent max(45%, 780px));
  transition: opacity 0.6s ease;
}
/* Chris, 26 Oct: the fade is there for the text. When the column steps aside for the flight, it goes with it, so the
   map is whole edge to edge from then on (the records' wait included). It comes back with the column. */
.screen-welcome:has(.landing-column.is-flying) .landing-fade { opacity: 0; transition: opacity 0.3s ease-out; }
/* .screen-welcome prefix: maplibre-gl.css (loaded later) sets .maplibregl-map to
   position:relative, which would collapse the container to zero height. */
.screen-welcome .landing-map {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;                     /* arrival 0–0.4 s: cream, wordmark, coastline fade in */
  transition: opacity 0.4s ease-out;
}
.landing-map.is-ready { opacity: 1; }
.landing-map .maplibregl-canvas { outline: none; }
.landing-map .maplibregl-ctrl-bottom-right { z-index: 1; }
.landing-map .maplibregl-ctrl-attrib {
  font-family: var(--font-detail);
  font-size: 10px;
  color: var(--ink-soft);
  background: transparent;
}
.landing-map .maplibregl-ctrl-attrib a { color: inherit; }

/* Hand-over (Part 3): the landing stays painted above the review screen and fades out
   over 300 ms — the cross-fade — after navigateTo() has already shown the review beneath.
   Both selectors carry !important so this wins over .hidden's display:none. */
.screen-welcome.landing-fading {
  display: block !important;
  position: fixed !important;
  inset: 0;
  z-index: 90;
  pointer-events: none;
  transition: opacity 0.3s ease-out;
}
.screen-welcome.landing-fading.is-gone { opacity: 0; }

/* Brief 19 — the hand-over to the twin: a diagonal wipe, bottom-left → top-right.
   landing.js writes --w (-22 % → 100 %) once a frame; registered so it is a real <percentage>,
   and inherits: false so a write restyles this element only, never the column inside it. */
@property --w {
  syntax: '<percentage>';
  inherits: false;
  initial-value: -22%;
}
/* Reduced motion, to the twin: no wipe — a plain 300 ms opacity cross-fade (opacity, not
   movement, so it stays even under the reduced-motion rule that makes .landing-fading instant). */
.screen-welcome.landing-fading.landing-crossfade { transition: opacity 0.3s ease-out; }
.screen-welcome.landing-wiping {
  -webkit-mask-image: linear-gradient(to top right, transparent var(--w), #000 calc(var(--w) + 22%));
  mask-image: linear-gradient(to top right, transparent var(--w), #000 calc(var(--w) + 22%));
}

/* ---- the column ---- */
/* Chris, 24 Oct: the text jumped up once everything loaded. The column was centred (top 50%, translateY(-50%)),
   so anything that joined it after it showed — the saved schools for a signed-in visitor, the sign-in line —
   lifted the headline by half its height. The TOP is fixed now, where the signed-out column's centre used to
   put it (its 365 px stack, so 50% − 182 px), and what joins the column grows downward. */
.landing-column {
  position: absolute;
  z-index: 2;
  left: 64px;
  /* Brief 50 A1: the headline starts about a third of the way down; on a short window it rises so the stack (about
     470 px) still ends above the credit. The column is 520 px at most. Linzie, 28 Oct: a little higher, about 28 %. */
  top: max(88px, min(28%, calc(100% - 560px)));
  width: 520px;
  max-width: calc(100% - 32px);
}
/* Arrival order (Chris, 30 Sep): the map first — cream + coastline — THEN the column, THEN the
   dots. landing.js adds .is-in once the style is parsed and sign-in availability is known, so
   nothing in the column appears and then moves. */
.landing-stack { opacity: 0; }
.landing-stack.is-in { opacity: 1; }
/* Chris (30 Sep): the column builds one line at a time — each .landing-rise lifts in 130 ms
   after the one before it (--i is its beat), like lines layering up. */
.landing-rise { opacity: 0; }
.landing-headline .landing-rise { display: inline-block; }
.landing-stack.is-in .landing-rise {
  animation: landingIn 0.55s cubic-bezier(0.2, 0.7, 0.2, 1) both;
  animation-delay: calc(var(--i, 0) * 130ms);
}
@keyframes landingIn {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Brief 50 A1: the headline wraps inside the 520 px column (text sits on solid ground, never on the dots). Linzie, 28 Oct:
   the search sits right under the headline, and the line is a small note under the search (the results drop over it). */
.landing-headline {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(34px, 3.2vw, 48px);
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--landing-headline, var(--brand-green));
  margin: 0 0 28px;
}
.landing-sub {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.5;
  color: var(--landing-line, var(--ink-soft));
  margin: 40px 0 0;               /* Linzie, 8 Nov: the same breathing space as between the line and the buttons */
  /* Linzie, 8 Nov: flush with the headline's left edge (no indent to the box's rounded start). */
}

/* ---- search: 56 px pill with the glyph ---- */
/* z-index: the line-rise transform makes each row its own stacking context, so the dropdown
   must be lifted at the row level to sit over the credit / sign-in / cards below it. */
.landing-search { position: relative; z-index: 5; max-width: none; margin: 0; }
/* While results are showing, what sits under the dropdown steps out of the way
   (visibility, not opacity — the rise animation's fill owns opacity). */
.landing-search:has(.search-results.visible) ~ .landing-links,
.screen-welcome:has(.search-results.visible) .landing-credit,
.screen-welcome:has(.search-results.visible) .landing-legend { visibility: hidden; }
/* Brief 50 A1: the orange arrow button at the box's right end; it runs the search (or opens the active result). */
.landing-search-go {
  position: absolute;
  right: 6px;
  top: 6px;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--brand-orange);
  color: var(--surface);
  cursor: pointer;
  transition: filter 0.15s ease;
}
.landing-search-go:hover { filter: brightness(1.06); }
.landing-search-go:focus-visible { outline: 3px solid var(--landing-focus, var(--brand-green)); outline-offset: 2px; }
.landing-search-glyph {
  position: absolute;
  left: 16px;
  top: 17px;
  color: var(--ink-soft);
  pointer-events: none;
  z-index: 1;
}
.landing-search .search-input {
  height: 56px;
  padding: 0 56px 0 48px; /* the arrow button's room on the right; the placeholder fits whole in 520 px at 17 px */
  border-radius: 999px;
  border: 1.5px solid var(--landing-search-border, var(--line)); /* A3: the light landing's box is outlined orange */
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 17px;
  box-shadow: 0 8px 28px rgba(46, 46, 46, 0.08), 0 1px 3px rgba(46, 46, 46, 0.05);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.landing-search .search-input:focus {
  border-color: var(--brand-green);
  box-shadow: 0 8px 28px rgba(46, 46, 46, 0.10), 0 0 0 4px rgba(35, 85, 70, 0.12);
}
.landing-search .search-input::placeholder { color: var(--ink-soft); opacity: 0.8; }
.landing-search .search-results {
  border-radius: 12px;
  background: var(--surface);
  backdrop-filter: none;
  box-shadow: 0 12px 40px rgba(46, 46, 46, 0.12), 0 2px 8px rgba(46, 46, 46, 0.06);
  border: 1px solid var(--line);
  padding: 6px;
  max-height: min(64vh, 520px);
}
/* Brief 146: the count (and the town buttons) stay at the top; only the list scrolls. */
.landing-search .search-results.visible { display: flex; flex-direction: column; }
.landing-search .search-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; scrollbar-gutter: stable; }
.landing-search .search-head {
  flex: 0 0 auto;
  padding: 10px 14px 12px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--line);
}
.landing-search .search-head-title {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 15px;
  line-height: 21px;
  color: var(--brand-green);
}
.landing-search .search-head-sub {
  font-family: var(--font-detail);
  font-size: 13px;
  line-height: 18px;
  color: var(--ink-soft);
  margin-top: 2px;
}
.landing-search .search-towns { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.landing-search .search-town {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 18px;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}
.landing-search .search-town:hover { border-color: var(--brand-green); }
.landing-search .search-town-n { font-weight: 600; color: var(--ink-soft); }
/* Linzie's rule: orange always carries white text. */
.landing-search .search-town.is-on { background: var(--brand-orange); border-color: var(--brand-orange); color: var(--surface); }
.landing-search .search-town.is-on .search-town-n { color: var(--surface); }
.landing-search .search-town:focus-visible { outline: 3px solid var(--brand-orange); outline-offset: 2px; }
.landing-search .search-town-type {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  padding: 0 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--ink-soft);
}
.landing-search .search-town-type input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 7px 0;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 13px;
}
.landing-search .search-town-type:focus-within { border-color: var(--brand-green); }
.landing-search .search-result-distance {
  flex: 0 0 auto;
  font-family: var(--font-detail);
  font-weight: 600;
  font-size: 13px;
  color: var(--brand-green);
  white-space: nowrap;
}

/* Brief 146: a postcode's "You are here" pin on England (landing.js setPin). */
.landing-pin { display: flex; flex-direction: column; align-items: center; pointer-events: none; }
.landing-pin-label {
  margin-bottom: 6px;
  padding: 5px 12px;
  border: 1.5px solid var(--brand-orange);
  border-radius: 999px;
  background: var(--surface);
  color: var(--brand-orange);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 13px;
  white-space: nowrap;
  box-shadow: 0 4px 14px rgba(16, 46, 42, 0.3);
}
/* Linzie, 3 Nov: the pin is orange (a white dot in it), its label an orange-outlined pill with orange words. */
.landing-pin-mark { filter: drop-shadow(0 3px 5px rgba(16, 46, 42, 0.4)); }
.landing-pin-mark path { fill: var(--brand-orange); stroke: var(--surface); stroke-width: 1.5; }
.landing-pin-mark circle { fill: var(--surface); }
/* results: glyph · name / town · postcode · phase · arrow. Active = hover or arrow key —
   the same row the map enlarges. */
.landing-search .search-result-item {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  border: 0;
  border-radius: 10px;
  transition: background 0.15s ease;
}
.landing-search .search-result-item + .search-result-item { margin-top: 2px; }
.landing-search .search-result-item:hover,
.landing-search .search-result-item.is-active,
.landing-search .search-result-item:focus-visible {
  background: color-mix(in srgb, var(--brand-orange) 14%, var(--surface));
  outline: none;
}
.landing-links a:focus-visible,
.landing-search .search-input:focus-visible {
  outline: 3px solid var(--brand-orange);
  outline-offset: 2px;
}
.landing-search .search-result-glyph { flex: 0 0 auto; color: var(--brand-green); }
.landing-search .search-result-item.is-active .search-result-glyph { color: var(--brand-orange); }
.landing-search .search-result-text { flex: 1 1 auto; min-width: 0; }
.landing-search .search-result-name {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 22px;
  color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.landing-search .search-result-meta {
  font-family: var(--font-detail);
  font-size: 13px;
  line-height: 18px;
  color: var(--ink-soft);
  margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.landing-search .search-result-arrow {
  flex: 0 0 auto;
  color: var(--brand-orange);
  font-size: 18px;
  opacity: 0;
  transition: opacity 0.15s ease;
}
.landing-search .search-result-item.is-active .search-result-arrow { opacity: 1; }
.landing-search .search-result-empty { cursor: default; }
.landing-search .search-result-empty:hover { background: transparent; }

/* Linzie, 28 Oct: hovering an orange dot shows a small card: the school's name, then a fact or two (landing.js). */
.landing-dot-card { pointer-events: none; z-index: 3; }
.landing-dot-card .maplibregl-popup-content {
  padding: 10px 14px;
  border-radius: 10px;
  background: var(--surface);
  box-shadow: 0 8px 24px rgba(16, 46, 42, 0.28);
}
.landing-dot-card-name {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 15px;
  line-height: 1.3;
  color: var(--ink);
}
.landing-dot-card-fact {
  margin: 2px 0 0;
  font-family: var(--font-detail);
  font-size: 13px;
  line-height: 1.4;
  color: var(--ink-soft);
}

/* Brief 50 A1 with Chris's ruling (25 Oct): the two buttons under the search, about twice the gap of before. */
.landing-links {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 40px 0 0;
}
.landing-button {
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  padding: 0 24px;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 600;
  color: var(--surface);
  text-decoration: none;
  white-space: nowrap;
  transition: filter 0.15s ease-out;
}
.landing-button--green { background: var(--brand-green); }
.landing-button--orange { background: var(--brand-orange); color: var(--on-orange, #FFFFFF); }
.landing-button:hover,
.landing-button:focus-visible { filter: brightness(1.08); }

/* ---- walkthrough 2 item 1: the gathering bar — the twin dock's box (story.css .dock: bottom-centre, 760 wide), shown
   while the dot pulses at the school and the twin gathers its records beneath. A strip slides while it waits. ---- */
.landing-dock {
  position: absolute;
  z-index: 3;
  left: 50%;
  bottom: 60px;
  width: 760px;
  max-width: calc(100% - 32px);
  box-sizing: border-box;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 14px 20px;
  border-radius: 16px;
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.08);
  animation: landing-dock-in 420ms ease-out both;
}
.landing-dock[hidden] { display: none; }
@keyframes landing-dock-in {
  from { opacity: 0; transform: translate(-50%, 8px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}
.landing-dock-icon {
  flex: none;
  display: inline-flex;
  color: var(--brand-green);
  padding-right: 20px;
  border-right: 1px solid var(--rule, rgba(0, 0, 0, 0.1));
}
.landing-dock-voice { flex: 1 1 auto; min-width: 0; }
.landing-dock-text {
  margin: 0 0 10px;
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 500;
  color: var(--ink);
}
/* Brief 67 P4: each new line of what has been found fades in. */
.landing-dock-text.is-new { animation: landing-dock-say 360ms ease-out both; }
@keyframes landing-dock-say { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .landing-dock-text.is-new { animation: none; } }
.landing-dock-strip {
  position: relative;
  display: block;
  height: 3px;
  overflow: hidden;
  background: var(--rule, rgba(0, 0, 0, 0.1));
}
.landing-dock-strip > span {
  position: absolute;
  inset: 0 auto 0 0;
  width: 28%;
  background: var(--brand-orange);
  animation: landing-dock-slide 1.4s ease-in-out infinite;
}
@keyframes landing-dock-slide {
  from { transform: translateX(-100%); }
  to { transform: translateX(360%); }
}
@media (prefers-reduced-motion: reduce) {
  .landing-dock { animation: none; }
  .landing-dock-strip > span { animation: none; width: 33%; }
}

/* ---- Brief 50 A6: the map's legend, quiet: bottom-right above the attribution on a wide window, above the buttons
   on a narrow one; it fades in with the column and goes with the flight. ---- */
.landing-legend {
  position: absolute;
  z-index: 2;
  right: 24px;
  bottom: 44px;
  max-width: 400px;
  display: block;
  margin: 0;
  padding: 6px 10px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--landing-ground, var(--surface)) 82%, transparent); /* never on the dots */
  font-family: var(--font-body);
  font-size: 12.5px;
  line-height: 1.45;
  text-align: right;
  color: var(--landing-line, var(--ink-soft));
  opacity: 0;
  transition: opacity 0.4s ease-out;
}
.landing-legend[hidden] { display: none; }
.landing-legend b { font-weight: 600; color: var(--landing-headline, var(--ink)); font-variant-numeric: tabular-nums; }
.landing-legend-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 7px;
  border-radius: 50%;
  background: var(--landing-dot, var(--brand-green));
  vertical-align: 0;
}
.screen-welcome:has(.landing-stack.is-in) .landing-legend { opacity: 1; }
.screen-welcome:has(.landing-column.is-flying) .landing-legend { opacity: 0; transition: opacity 0.3s ease-out; }
@media (max-width: 1023px) {
  .landing-legend { left: 6px; right: 6px; bottom: 124px; max-width: none; text-align: left; font-size: 12px; }
}

/* ---- maker's credit: the page's bottom-left corner (Chris, 24 Oct), the weight of the map attribution ----
   Outside the column, so it fades in with the column (no rise of its own) and out with the flight. */
.landing-credit {
  position: absolute;
  z-index: 2;
  left: 64px;                   /* flush with the column's text */
  bottom: 24px;
  opacity: 0;
  transition: opacity 0.4s ease-out, color 0.15s ease;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  font-family: var(--font-body);
  font-size: 15px;              /* Brief 49 §1: larger than #85's 13 px */
  line-height: 22px;
  color: var(--landing-line, var(--ink-soft));
  text-decoration: none;
}
.screen-welcome:has(.landing-stack.is-in) .landing-credit { opacity: 1; }
.screen-welcome:has(.landing-column.is-flying) .landing-credit { opacity: 0; pointer-events: none; transition: opacity 0.3s ease-out; }
/* Brief 169: Help · Terms · Privacy · Cookies, under the credit, fading in and out with it. */
.landing-legal {
  position: absolute; z-index: 2; left: 64px; bottom: 0;
  display: flex; gap: 14px; opacity: 0; transition: opacity 0.4s ease-out;
  font-family: var(--font-body); font-size: 12px; line-height: 18px;
}
.landing-legal a { display: inline-block; padding: 3px 0; color: var(--landing-line, var(--ink-soft)); text-decoration: none; } /* Brief 167: 24 px tall, big enough to tap */
.landing-legal a:hover, .landing-legal a:focus-visible { color: var(--landing-headline, var(--ink)); text-decoration: underline; }
.landing-legal a:focus-visible { outline: 3px solid var(--brand-orange); outline-offset: 2px; border-radius: 4px; }
.screen-welcome:has(.landing-stack.is-in) .landing-legal { opacity: 1; }
.screen-welcome:has(.landing-column.is-flying) .landing-legal,
.screen-welcome:has(.search-results.visible) .landing-legal { opacity: 0; pointer-events: none; transition: opacity 0.3s ease-out; }
@media (max-width: 767px) { .landing-legal { left: 16px; bottom: 0; padding-bottom: env(safe-area-inset-bottom, 0); } }
/* The lockup reads like the logo: roundel · NET ZERO (Stolzl Medium) · ADVISORY (Stolzl Light). */
.landing-credit-name {
  font-family: var(--font-display);
  font-size: 14px;
  line-height: 22px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  white-space: nowrap;
}
.landing-credit-nz { font-weight: var(--w-medium); }
.landing-credit-adv { font-weight: var(--w-light); }
.landing-credit:hover,
.landing-credit:focus-visible { color: var(--landing-headline, var(--ink)); outline: 3px solid var(--brand-orange); outline-offset: 4px; border-radius: 6px; }
/* A2: on forest the green button keeps its green, ringed in mint so it stands off the ground. */
.screen-welcome[data-landing="forest"] .landing-button--green { box-shadow: inset 0 0 0 1.5px var(--mint); }
/* A2: the top bar over the forest landing: the roundel and the rule in white, the wordmark's on-dark copy. */
body.on-welcome:has(#screenWelcome[data-landing="forest"]) .topbar-nza::before,
body.on-welcome:has(#screenWelcome[data-landing="forest"]) .topbar-brand-rule { background: var(--surface); }
body.on-welcome:has(#screenWelcome[data-landing="forest"]) .topbar-logo { background-image: url('/assets/decoded-logo-on-dark.svg'); }
.screen-welcome[data-landing="forest"] .landing-map .maplibregl-ctrl-attrib,
.screen-welcome[data-landing="forest"] .landing-map .maplibregl-ctrl-attrib.maplibregl-compact {
  color: var(--forest-line);
  background: var(--forest);
}
.screen-welcome[data-landing="forest"] .landing-map .maplibregl-ctrl-attrib-button { filter: invert(1); }
/* The roundel only: nza-logo.svg is the 1000×120 wordmark in its own grey, so it is drawn as
   a currentColor mask and the window is cropped to the mark (x 22–138 of the viewBox). */
.landing-credit-mark {
  flex: 0 0 auto;
  width: 23px;                  /* Brief 49 §1: the 18 px crop scaled to 24 */
  height: 24px;
  background: currentColor;
  -webkit-mask: url('/assets/nza-logo.svg') no-repeat -4.4px 50% / 200px 24px;
  mask: url('/assets/nza-logo.svg') no-repeat -4.4px 50% / 200px 24px;
}

/* Flight: the column (headline, search, credit) steps aside so the travel is the map's. */
.landing-column.is-flying {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease-out;
}

/* ---- no map: the search-only landing (landing.js degradeToSearchOnly) ----
   Shown when the browser cannot run MapLibre (no WebGL2, or the constructor threw).
   The column is revealed with no arrival sequence and this note says what is missing;
   the empty map container is hidden so it cannot eat clicks. */
.screen-welcome.no-map .landing-map { display: none; }
.landing-nomap {
  margin-top: 20px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--brand-orange);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink-soft);
  font-size: 14px;
  line-height: 1.5;
  max-width: 440px;
}

/* ---- sign-in overlay over the map: the map dims 20 %, nothing else moves ---- */
body.on-welcome .auth-overlay {
  background: rgba(46, 46, 46, 0.2);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.landing-sr {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---- topbar while on the landing: wordmark top-left, quiet sign-in top-right ---- */
body.on-welcome .topbar {
  background: transparent;
  border-bottom-color: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
body.on-welcome .topbar-login-btn {
  padding: 9px 18px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: 14px;
  box-shadow: 0 2px 10px rgba(46, 46, 46, 0.06);
}
body.on-welcome .topbar-login-btn:hover { border-color: var(--ink-soft); }

/* ---- Brief 50 A4, as Chris ruled (25 Oct: "I definitely want the map there … it's really important"): under 1024 px
   the map stays, between the column's top (headline, search) and its foot (the two buttons, side by side), with the
   ground solid behind both and fading over the map, so no text sits on the dots. landing.js fits England into the
   middle (englandPadding). ---- */
@media (max-width: 1023px) {
  .landing-column {
    top: 76px;
    bottom: 60px;
    display: flex;
  }
  .landing-stack {
    display: flex;
    flex-direction: column;
    width: 100%;
  }
  .landing-stack.is-in .landing-links { margin-top: auto; }
  .landing-links { margin-top: auto; flex-direction: row; }
  /* --fade-top: where the column's top half (headline, line, search) ends: about 480 px on a tablet, 290 on a phone. */
  .landing-fade {
    --fade-top: 480px;
    background:
      linear-gradient(180deg, var(--landing-ground) 0, var(--landing-ground) var(--fade-top), transparent calc(var(--fade-top) + 56px)),
      linear-gradient(0deg, var(--landing-ground) 0, var(--landing-ground) 172px, transparent 216px); /* the buttons, the credit and the legend (A6) */
  }
}
@media (max-width: 767px) {
  body.on-welcome .topbar { padding: 0 16px; }
  body.on-welcome .topbar-brand { gap: 10px; }
  body.on-welcome .topbar-logo { width: 132px; height: 36px; }
  .landing-fade { --fade-top: 290px; }
}
/* ---- phone ---- */
@media (max-width: 767px) {
  .landing-column {
    left: 16px;
    right: 16px;
    width: auto;
    max-width: none;
    top: 84px;
    transform: none;
  }
  .landing-headline { font-size: 28px; line-height: 1.15; margin-bottom: 20px; }
  .landing-sub { display: none; } /* Chris: on a phone the line goes; the map says it */
  .landing-links { gap: 10px; }
  .landing-button { flex: 1 1 0; justify-content: center; min-height: 44px; padding: 0 14px; font-size: 15px; }
  .landing-search .search-input { font-size: 16px; }
  .landing-credit { left: 16px; bottom: calc(26px + env(safe-area-inset-bottom, 0px)); } /* Brief 167: clear of the 24 px legal links */
}

/* ---- reduced motion: everything at once, nothing moves ---- */
@media (prefers-reduced-motion: reduce) {
  .landing-map { transition: none; opacity: 1; }
  .landing-stack, .landing-stack.is-in { animation: none; opacity: 1; }
  .landing-rise, .landing-stack.is-in .landing-rise { animation: none; opacity: 1; transform: none; }
  .screen-welcome.landing-fading { transition: none; }
  .landing-column.is-flying { transition: none; }
  .landing-credit { transition: none; }
}

/* ========================================
   THE TWIN (Brief 20) — decodED's own, mounted on this page
   The NZA twin in a full-screen iframe: the same box as the landing map, under the topbar
   (z 100) and under the raised landing (z 90) until the wipe uncovers it.
   ======================================== */
.screen-twin {
  position: fixed;
  inset: 0;
  z-index: 10;
  padding-top: 0;                 /* the twin's map fills the whole viewport; its UI starts at `inset` */
  background: var(--land);
}
.twin-mount, .twin-mount iframe {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  border: 0;
  display: block;
}
/* On the twin: decodED's standard bar (its ground + blur — the wordmark is green on a busy
   satellite), one palette (no theme toggle), and the school name as a label, not a menu. */
body.on-twin .topbar-school { pointer-events: none; }
body.on-twin .topbar-school::after { content: none; }
/* A long name ("Holy Island Church of England Prima") was cut mid-word: text-overflow needs a block box, not the
   inline-flex the arrow wants, and on the twin there is no arrow. */
body.on-twin .topbar-school { display: block; }
body.on-twin .topbar-logo { cursor: pointer; }
/* Linzie (3 Nov): Sign in and Sign up sit top right on every page. On a phone's twin the bar makes room for them:
   the logo alone (no NZA mark, no school name, which the twin shows itself), Our story as its icon (shell.css). */
@media (max-width: 760px) {
  body.on-twin .topbar { padding: 0 12px; }
  body.on-twin .topbar-nza,
  body.on-twin .topbar-brand-rule,
  body.on-twin .topbar-school-wrap { display: none; }
  body.on-twin .topbar-logo { width: 110px; }
  body.on-twin .topbar-right { gap: 8px; }
  body.on-twin .topbar-login-btn { padding: 8px 12px; }
  /* Brief 235: with two or more schools the name stays (it is the school switcher), so it gives way, cut short, and
     My decodED always fits. */
  body.on-twin .topbar-right { min-width: 0; flex: 1 1 auto; justify-content: flex-end; }
  body.on-twin .topbar-login-btn, body.on-twin .topbar-pro-chip { flex: none; }
  body.on-twin.has-school-switch .topbar .topbar-school-wrap { flex: 0 1 auto; min-width: 0; }
  body.on-twin.has-school-switch .topbar-school { min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
}
/* Brief 128 (Linzie, 2 Nov: "the NZA logo sits centred to [the left bar] … the line that's breaking the NZA icon and the
   decodED icon aligns with the right-hand side of the navigation bar"): on a laptop, where the module rail stands, the
   roundel is centred over the rail and the rule falls on the rail's right edge (its 1 px border, the rail's last pixel).
   The roundel is 31 px wide; the bar's gap is 14 px. */
@media (min-width: 761px) {
  body.on-twin .topbar { padding-left: calc((var(--rail-width) - 31px) / 2); }
  body.on-twin .topbar-nza { margin-right: calc(var(--rail-width) - 1px - (var(--rail-width) - 31px) / 2 - 31px - 14px); }
}

/* The twin couldn't make a site: a small decodED card on the cream, and a way back. */
.twin-error {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 360px;
  max-width: calc(100% - 32px);
  box-sizing: border-box;
  padding: 24px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  box-shadow: 0 12px 40px rgba(46, 46, 46, 0.12), 0 2px 8px rgba(46, 46, 46, 0.06);
  z-index: 1;
}
.twin-error[hidden] { display: none; }
.twin-error-title {
  font-family: var(--font-display);
  font-weight: var(--w-medium);
  font-size: 24px;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--brand-green);
  margin: 0 0 8px;
}
.twin-error-body {
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 26px;
  color: var(--ink-soft);
  margin: 0 0 20px;
}
.twin-error-back {
  width: 100%;
  height: 56px;
  border: 0;
  border-radius: 12px;
  background: var(--brand-green);
  color: var(--surface);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(35, 85, 70, 0.22);
}
.twin-error-back:hover { filter: brightness(1.08); }
.twin-error-back:focus-visible { outline: 3px solid var(--brand-orange); outline-offset: 2px; }

/* Linzie, 7 Nov 2026 ("one screen … a straight take me in"): an /explore address opens on the twin at once, so the landing
   (the forest map with its pulsing dot) never shows on the way. public/straight-in.js sets the class before the first paint;
   app.js openStraightIn takes it off once the twin screen is up. */
.straight-in .screen-welcome { visibility: hidden; }
.straight-in body { background: var(--land, #F4F1EA); }
