/* ═══════════════════════════════════════════════════════════════════════════
   Purple Real Estate — the whole design layer.

   Direction A's layout on the Purple Group design system (Direction B).
   Tokens below are transcribed from HANDOFF.md §4, which is the agreed source.

   THE SYSTEM IS CLOSED. No colour, weight, radius or spacing value exists here
   that is not in the token block. Adding one is a design decision, not a CSS
   change — see CLAUDE.md § The design system is closed.

   No gradients. No shadows. No emoji. No unicode icon characters. Icons are
   inline Lucide SVG at stroke-width 1.5.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Palette. Blue Violet is the SINGLE accent; there is no second. ── */
  --ink:      #021B2A;   /* Ink Black — the ground */
  --cloud:    #F5FDFF;   /* Cloudy White — body and heading ink */
  --violet:   #7C3AED;   /* Blue Violet — actions, tags, eyebrow rule */
  --teal:     #053A4D;   /* Dark Teal — hairlines, ghost-button border */
  --frost:    #A6E1FA;   /* Frosted Blue — eyebrows, cadastral line */
  --dim:      #8FA7B4;   /* dimmed body on the dark ground */
  --dim-light:#4A6270;   /* dimmed body on a LIGHT band. --dim cannot do this job:
                            #8FA7B4 on Cloudy White is ~2.2:1. Same teal bias,
                            darkened until it clears AA — measures 6.2:1. */
  --ink-82:   rgba(2, 27, 42, 0.82);  /* flat panel over photography, never a gradient */

  /* ── Type. One sans throughout. Hanken Grotesk stands in for Greycliff CF
        until the licensed files land — see HANDOFF.md §3. ── */
  --sans: 'Hanken Grotesk', 'Avenir Next', Avenir, ui-sans-serif, system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ── Radii. Photography 16px and always rectangular; UI chrome 4px. ── */
  --r-photo: 16px;
  --r-ui: 4px;

  /* ── Spacing scale ── */
  --gut: clamp(20px, 5vw, 64px);   /* page side gutter */
  --sec: clamp(64px, 9vw, 128px);  /* section rhythm */

  /* ── Motion ── */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --t-fast: 120ms;
  --t-mid: 220ms;
  --t-slow: 480ms;

  color-scheme: dark;
}

/* The site commits to one look: a dark ground is the brand, not a theme. */

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--ink);
  color: var(--cloud);
  font-family: var(--sans);
  font-weight: 400;
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

/* Focus is never removed. 2px Blue Violet at 2px offset. */
:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 2px;
  border-radius: 2px;
}

h1, h2, h3, h4, h5 {
  margin: 0;
  font-weight: 500;
  letter-spacing: -0.025em;
  line-height: 0.98;   /* headlines only; sentence case, never Title Case */
}
p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }

.wrap { max-width: 1320px; margin: 0 auto; padding-inline: var(--gut); }

/* The eyebrow signature: 700, 0.18em, ALL CAPS, Frosted Blue.
   Non-negotiable per brand.md. */
.eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--frost);
  line-height: 1.5;
  margin: 0;
}
.eyebrow--rule {
  padding-left: 16px;
  border-left: 2px solid var(--violet);
}

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

/* Skip link — visible only on focus, lands on the main content. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--violet); color: var(--cloud);
  padding: 12px 20px; border-radius: var(--r-ui);
  font-size: 13px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
}
.skip:focus { left: var(--gut); top: 12px; }

/* ── Buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  border-radius: var(--r-ui);
  transition: background var(--t-mid) var(--ease), border-color var(--t-mid) var(--ease),
              color var(--t-mid) var(--ease);
  white-space: nowrap;
}
.btn--solid {
  color: var(--cloud);
  background: var(--violet);
  padding: 16px 28px;
  border: 1px solid var(--violet);
}
.btn--solid:hover { background: #6D28D9; border-color: #6D28D9; }
.btn--ghost {
  color: var(--cloud);
  border: 1px solid var(--teal);
  padding: 16px 28px;
}
.btn--ghost:hover { border-color: var(--frost); }
.btn--sm { padding: 13px 20px; font-size: 11px; }

/* ═══ NAV ═══════════════════════════════════════════════════════════════════
   A LIGHT masthead band above the dark page, which is what lets the supplied
   brand logo be used as drawn. Purple #55307F on Ink Black measures about 1.6:1
   — nowhere near legible — so the original artwork needs a light ground. The
   derived white knockout existed only to work around that.

   Proportions measured off purple.group at 1440px: 94px tall, content spanning
   1376px of a 1440px viewport (≈32px gutters, far wider than the body grid), and
   nav links set in caps at 700 rather than sentence case — which is also this
   brand's own eyebrow signature.
   ═══════════════════════════════════════════════════════════════════════════ */
.nav {
  position: sticky; top: 0; z-index: 50;
  background: var(--cloud);
  /* No bottom hairline: the step down to the Ink Black hero is the edge. */
}
/* The masthead runs wider than the body grid — see the measurement above. */
.nav__inner {
  display: flex; align-items: center; gap: 32px;
  max-width: 1600px; margin: 0 auto;
  padding-inline: clamp(20px, 3vw, 44px);
  min-height: 94px;
}
.nav__logo { height: 38px; width: auto; }

.nav__links { display: flex; gap: 30px; margin-left: auto; align-items: center; }
.nav__links a {
  font-size: 13px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink);
  transition: color var(--t-fast) var(--ease);
  padding-block: 4px;
}
.nav__links a:hover { color: var(--violet); }
/* The menu carries its own CTA for the mobile panel, where .nav__cta is hidden.
   Above the breakpoint that copy is a DUPLICATE of .nav__cta and must not paint. */
.nav__links .btn { display: none; }

.nav__toggle {
  display: none; margin-left: auto;
  background: none; border: 1px solid var(--teal); border-radius: var(--r-ui);
  color: var(--ink); padding: 9px; cursor: pointer;
}

@media (max-width: 960px) {
  .nav__inner { min-height: 72px; }
  .nav__logo { height: 30px; }
  .nav__toggle { display: inline-flex; }
  .nav__cta { display: none; }
  .nav__links {
    display: none;
    position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column; gap: 0; align-items: stretch;
    background: var(--cloud);
    padding: 8px clamp(20px, 3vw, 44px) 24px;
  }
  .nav__links[data-open='true'] { display: flex; }
  .nav__links .btn { display: block; }
  .nav__links a { padding-block: 15px; border-bottom: 1px solid rgba(5, 58, 77, 0.14); }
  .nav__links .btn { margin-top: 18px; text-align: center; border-bottom: 0; }
}

/* ═══ HERO ═════════════════════════════════════════════════════════════════
   Type on a flat ground BESIDE the photograph, never over it. This is the
   structural fix for the live site's white-on-light failure — see HANDOFF §6.1.
   ═════════════════════════════════════════════════════════════════════════ */
/* HEIGHT IS A FEATURE HERE. The cities strip sits at the bottom edge of the
   photograph, so the whole hero has to clear the fold on a laptop or that line is
   never seen. A 14in MacBook Pro leaves roughly 800px of viewport after browser
   chrome; minus the 94px masthead that is ~700px, so the hero targets ~610px and
   the strip lands well inside it. Adding vertical space back here pushes it off
   screen again — check a short viewport before growing any value below. */
.hero { display: grid; grid-template-columns: 1fr 0.92fr; align-items: stretch; }
.hero__type {
  display: flex; flex-direction: column;
  padding: clamp(36px, 4.4vw, 64px) clamp(28px, 4vw, 64px) clamp(30px, 3vw, 44px) var(--gut);
}
.hero h1 {
  font-size: clamp(32px, 4.6vw, 62px);
  margin-top: 22px;
  max-width: 20ch;
  text-wrap: balance;
}
.hero__sub {
  margin-top: 20px; font-size: clamp(15.5px, 1.2vw, 18px);
  line-height: 1.5; color: var(--dim); max-width: 44ch;
}
.hero__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
.hero__img {
  position: relative; overflow: hidden; background: #08283A;
  /* WHAT ACTUALLY SETS THE HERO'S HEIGHT. Without an explicit height the <img>
     resolves height:100% against an indefinite track and falls back to its own
     aspect ratio at the column width — a near-square crop then dictated a 740px
     hero and pushed the cities strip below the fold on a 14in laptop.
     Capped so nav (94px) + hero always clears a short viewport. svh, not vh, so
     mobile browser chrome is counted. */
  height: clamp(340px, calc(100svh - 150px), 620px);
}
@supports not (height: 100svh) {
  .hero__img { height: clamp(340px, calc(100vh - 150px), 620px); }
}
/* `picture` is display:contents so the <img> still lays out as the direct child
   the cover sizing below assumes — the selector would otherwise miss it. */
.hero__img picture { display: contents; }
.hero__img img { width: 100%; height: 100%; object-fit: cover; }
.hero__cities {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 16px clamp(18px, 2vw, 28px);
  background: var(--ink-82);        /* flat panel, not a gradient scrim */
  display: flex; flex-wrap: wrap; gap: 6px 18px;
}
.hero__cities span {
  font-size: 11px; font-weight: 700; letter-spacing: 0.17em; text-transform: uppercase;
}
.hero__cities span:first-child { color: var(--frost); }

@media (max-width: 900px) {
  .hero { grid-template-columns: 1fr; }
  .hero__type { padding-inline: var(--gut); }
  /* Stacked: the photograph is a band under the type, not a full column. */
  .hero__img { height: clamp(260px, 42svh, 360px); }
}

/* ═══ SECTION SCAFFOLD ═════════════════════════════════════════════════════ */
.section { padding-block: var(--sec); border-top: 1px solid var(--teal); }
.section__head { max-width: 62ch; }
.section__head h2 { font-size: clamp(28px, 3.4vw, 46px); margin-top: 20px; text-wrap: balance; }
.section__head p { margin-top: 20px; color: var(--dim); font-size: 17px; line-height: 1.6; }

/* ═══ LISTINGS ═════════════════════════════════════════════════════════════
   Catalogue items, not boxed cards: image → hairline rule → price.
   No border, no shadow, so nothing competes with the photograph.

   EVERY LISTING LINKS OUT TO sreality.cz. That is the system of record; this
   site owns no listing data and has no detail pages. See ADR 0001.
   ═════════════════════════════════════════════════════════════════════════ */
.offers__head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: 12px 24px; padding-bottom: 20px; border-bottom: 1px solid var(--teal);
}
.offers__head a { font-size: 14px; color: var(--dim); border-bottom: 1px solid var(--teal); padding-bottom: 2px; }
.offers__head a:hover { color: var(--cloud); border-color: var(--frost); }

/* One horizontal strip, never a wrapping grid: the listing set is small and reads
   as a shelf. Cards hold 260px so four of them fit the 1320px wrap exactly; below
   that the strip scrolls sideways instead of stacking.
   The reveal sits on this container, not on each card (index.html) — a card
   scrolled out of this overflow box never intersects the viewport, so a per-item
   reveal would leave the right-hand cards permanently invisible. */
.grid {
  --offers-gap: clamp(24px, 3vw, 40px);
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(260px, 1fr);
  gap: var(--offers-gap); margin-top: 36px;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: thin; scrollbar-color: var(--teal) transparent;
}

/* The strip never moves on its own — the reader drags it. [data-drag] is set by
   site.js only while the cards actually overflow, so the grab cursor never
   promises a movement that cannot happen (all four fit at full desktop width). */
.grid[data-drag] { cursor: grab; }
.grid[data-press] { -webkit-user-select: none; user-select: none; }
.grid[data-dragging] { cursor: grabbing; scroll-snap-type: none; }

.item { display: flex; flex-direction: column; scroll-snap-align: start; }
.item__media {
  position: relative; border-radius: var(--r-photo); overflow: hidden;
  aspect-ratio: 4 / 3; max-width: 100%; background: #08283A;
}
.item__media img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform var(--t-slow) var(--ease);
}
.item:hover .item__media img { transform: scale(1.03); }
@media (prefers-reduced-motion: reduce) { .item:hover .item__media img { transform: none; } }

/* Empty state for a listing that has no photograph yet. KEPT ON PURPOSE even
   though all four current cards carry one: listings are refreshed from Sreality,
   whose image CDN returns 401, so every new listing arrives photo-less until Petr
   supplies the original. This is the recurring case, not a one-off.
   (This overrides an earlier note here that said to delete it once real photos
   landed — that was written before the refresh cycle was understood.)
   A flat panel with a label reads as deliberate rather than broken. */
.item__media--empty {
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--teal);
}
.item__soon {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--frost); opacity: 0.75;
}

.item__tag {
  position: absolute; left: 12px; top: 12px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.15em; text-transform: uppercase;
  color: var(--cloud); background: var(--violet);
  padding: 7px 11px; border-radius: var(--r-ui);
}
.item__body { padding-top: 18px; }
.item__body h3 { font-size: 19px; line-height: 1.26; letter-spacing: -0.015em; }
.item__loc { margin-top: 8px; font-size: 14px; color: var(--dim); }
.item__cad { margin-top: 4px; font-family: var(--mono); font-size: 12px; color: var(--frost); }
.item__price {
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--teal);
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
}
/* Prices are numbers again: tabular figures, non-breaking thousands separator
   in the markup, and no zero-width characters. See HANDOFF §6.3. */
.item__price b {
  font-size: 20px; font-weight: 600; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.item__price span {
  font-size: 12.5px; color: var(--dim);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.item__out {
  margin-top: 12px; font-size: 12px; color: var(--dim);
  display: inline-flex; align-items: center; gap: 6px;
}
.item:hover .item__out { color: var(--frost); }
.item__out svg { width: 14px; height: 14px; }

/* ═══ SERVICES ═════════════════════════════════════════════════════════════ */
.svc { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(28px, 3vw, 48px); margin-top: 48px; }
@media (max-width: 820px) { .svc { grid-template-columns: 1fr; } }
.svc__card { padding-top: 26px; border-top: 1px solid var(--teal); }
.svc__card h3 { font-size: 21px; margin-top: 18px; line-height: 1.2; }
.svc__icon { color: var(--frost); }
.svc__card ul { margin-top: 18px; display: flex; flex-direction: column; gap: 11px; }
.svc__card li {
  position: relative; padding-left: 20px; font-size: 15.5px; line-height: 1.5; color: var(--dim);
}
.svc__card li::before {
  content: ''; position: absolute; left: 0; top: 10px;
  width: 7px; height: 1px; background: var(--violet);
}

/* ═══ FAQ ══════════════════════════════════════════════════════════════════ */
.faq { margin-top: 44px; max-width: 900px; }
.faq__item { border-top: 1px solid var(--teal); }
.faq__item:last-child { border-bottom: 1px solid var(--teal); }
.faq__q {
  width: 100%; display: flex; align-items: flex-start; justify-content: space-between; gap: 24px;
  background: none; border: 0; color: var(--cloud);
  font-family: var(--sans); font-size: clamp(17px, 1.6vw, 20px); font-weight: 500;
  letter-spacing: -0.015em; line-height: 1.3; text-align: left;
  padding: 26px 0; cursor: pointer;
}
.faq__q:hover { color: var(--frost); }
.faq__sign { flex: none; width: 20px; height: 20px; margin-top: 3px; color: var(--violet);
  transition: transform var(--t-mid) var(--ease); }
.faq__q[aria-expanded='true'] .faq__sign { transform: rotate(45deg); }
/* Visible BY DEFAULT and collapsed by JS, never the reverse: without this file's
   script every answer must still be readable. Inverting these two rules is what
   turns the accordion into six dead buttons for a reader with no JS. */
.faq__a { display: block; padding-bottom: 28px; max-width: 72ch; color: var(--dim); line-height: 1.65; }
.faq__a[data-open='false'] { display: none; }
.faq__a strong { color: var(--cloud); font-weight: 600; }
.faq__a ul { margin-top: 12px; display: flex; flex-direction: column; gap: 8px; }
.faq__a li { position: relative; padding-left: 20px; }
.faq__a li::before {
  content: ''; position: absolute; left: 0; top: 13px; width: 7px; height: 1px; background: var(--violet);
}

/* ═══ REFERENCES ═══════════════════════════════════════════════════════════ */
.refs { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(24px, 3vw, 44px); margin-top: 48px; }
@media (max-width: 760px) { .refs { grid-template-columns: 1fr; } }
.ref { padding-top: 26px; border-top: 1px solid var(--teal); }
.ref blockquote { margin: 0; font-size: 18px; line-height: 1.55; letter-spacing: -0.01em; }
.ref figcaption { margin-top: 18px; font-size: 12px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--frost); }

/* ═══ CERTIFICATES + MAP ═══════════════════════════════════════════════════ */
.two { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 4vw, 64px); }
@media (max-width: 820px) { .two { grid-template-columns: 1fr; } }
.docs { margin-top: 30px; display: flex; flex-direction: column; gap: 2px; }
.doc {
  display: flex; align-items: center; gap: 14px;
  padding: 18px 0; border-top: 1px solid var(--teal);
  font-size: 15.5px; color: var(--dim);
  transition: color var(--t-fast) var(--ease);
}
.doc:last-child { border-bottom: 1px solid var(--teal); }
.doc:hover { color: var(--cloud); }
.doc svg { flex: none; color: var(--frost); }
.doc span { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--frost); }

/* ═══ LIGHT BAND ════════════════════════════════════════════════════════════
   A Cloudy White section on the Ink Black page. Introduced for Partneři, whose
   logos are other companies' marks supplied as white-background JPEGs — on the
   dark ground each needed its own white tile, which read as seven patches. On a
   light band they simply sit there.

   NO NEW COLOURS. The band re-roles existing tokens: Cloudy White becomes the
   ground, Ink Black the heading ink, Dark Teal the eyebrow and the dimmed body.
   Frosted Blue cannot carry the eyebrow here — #A6E1FA on #F5FDFF is about
   1.2:1 — so Dark Teal takes that job, the same swap the hairlines already make.
   ═══════════════════════════════════════════════════════════════════════════ */
.section--light {
  background: var(--cloud);
  color: var(--ink);
  border-top: 0;
}
.section--light .section__head .eyebrow { color: var(--teal); }
.section--light .section__head p { color: var(--dim-light); }

/* ═══ PARTNERS ══════════════════════════════════════════════════════════════ */
.partners {
  margin-top: 44px;
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(20px, 3vw, 40px) clamp(24px, 4vw, 56px);
  align-items: center;
}
@media (max-width: 900px) { .partners { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px) { .partners { grid-template-columns: repeat(2, 1fr); } }
.partner {
  display: flex; align-items: center; justify-content: center;
  min-height: 84px;
  transition: opacity var(--t-mid) var(--ease);
}
.partner:hover { opacity: 0.6; }
.partner img {
  max-height: 52px; width: auto; object-fit: contain;
  /* The supplied marks are JPEGs, so each carries a baked-in #FFFFFF box that
     still reads as a faint rectangle against Cloudy White (#F5FDFF). Multiply
     maps white onto the band exactly (white x bg = bg), so the box disappears
     while the mark itself is untouched. Logos whose own ground is coloured
     (ILO, Asociace, Zvládneme, Ubytovna) are near-unchanged, because the band
     is near-white. Not a gradient and not a shadow — the system bans those. */
  mix-blend-mode: multiply;
}

/* ═══ CONTACT ══════════════════════════════════════════════════════════════ */
.contact { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 4vw, 72px); align-items: start; }
@media (max-width: 820px) { .contact { grid-template-columns: 1fr; } }
/* Moved here from the hero, and materially bigger: 168px wide against the 64px
   thumbnail it replaced. A one-person brokerage competing on a human approach
   should show the person at a size you can actually read a face in, and the
   contact block is where that decision gets made. Photography stays a 16px
   rectangle — never masked into a circle. */
.contact__broker {
  display: flex; align-items: center; gap: 22px;
  margin-top: 34px;
}
.contact__broker img {
  width: 168px; height: 181px; flex: none;
  border-radius: var(--r-photo);
  object-fit: cover;
}
.contact__broker b {
  display: block; font-size: 20px; font-weight: 600;
  letter-spacing: -0.01em; line-height: 1.2;
}
.contact__broker span {
  /* No max-width: at 11px with 0.16em tracking the full title is ~230px and the
     column has ~410px beside the portrait, so it sits on one line. Constraining it
     broke it across three. */
  display: block; margin-top: 9px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--frost); line-height: 1.5;
}
@media (max-width: 480px) {
  .contact__broker { gap: 16px; }
  .contact__broker img { width: 124px; height: 134px; }
  .contact__broker b { font-size: 18px; }
}

.contact__lines { margin-top: 30px; display: flex; flex-direction: column; gap: 2px; }
.cline {
  display: flex; align-items: center; gap: 14px;
  padding: 18px 0; border-top: 1px solid var(--teal); font-size: 16px;
  transition: color var(--t-fast) var(--ease);
}
.cline:last-of-type { border-bottom: 1px solid var(--teal); }
a.cline:hover { color: var(--frost); }
.cline svg { flex: none; color: var(--frost); }
.contact__card { padding-top: 30px; border-top: 1px solid var(--teal); }
.contact__card dl { margin: 22px 0 0; display: grid; grid-template-columns: auto 1fr; gap: 10px 20px; }
.contact__card dt {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--frost); padding-top: 3px;
}
.contact__card dd { margin: 0; font-size: 15.5px; color: var(--dim); line-height: 1.5; }

/* ═══ FOOTER ════════════════════════════════════════════════════════════════
   Dark again, and carrying no logo. The masthead is sticky, so the mark never
   leaves the screen; repeating it at the bottom earned nothing, and hosting it was
   the only reason this band was ever light. Ink Black ground, Dark Teal hairline.
   ═══════════════════════════════════════════════════════════════════════════ */
.foot {
  border-top: 1px solid var(--teal);
  padding-block: 44px 52px;
}
.foot__inner {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 14px 48px;
}
.foot__group { font-size: 14.5px; line-height: 1.6; color: var(--dim); max-width: 46ch; }
.foot__group a {
  color: var(--cloud); font-weight: 600;
  border-bottom: 1px solid var(--violet); padding-bottom: 1px;
  transition: color var(--t-fast) var(--ease);
}
.foot__group a:hover { color: var(--frost); }

.foot__meta { margin-left: auto; font-size: 13.5px; color: var(--dim); }
.foot__meta a { border-bottom: 1px solid var(--teal); }
.foot__meta a:hover { color: var(--cloud); border-color: var(--frost); }

@media (max-width: 680px) {
  .foot__inner { flex-direction: column; align-items: flex-start; }
  .foot__meta { margin-left: 0; }
}

/* ═══ REVEAL ═══════════════════════════════════════════════════════════════
   Enhancement only. Without JS every section is visible — .reveal gets its
   visible state from JS adding [data-ready], never the reverse.
   ═════════════════════════════════════════════════════════════════════════ */
[data-ready] .reveal { opacity: 0; transform: translateY(14px); }
[data-ready] .reveal[data-seen='true'] {
  opacity: 1; transform: none;
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  [data-ready] .reveal { opacity: 1; transform: none; }
}
