/* ============================================================
   page.css — "ALLHAUS" layout.
   Load order: bootstrap -> theme.css -> page.css

   Full-bleed. Colour bands and media run edge to edge; only text
   columns are constrained. Vertical rhythm alternates
   white -> dark -> white -> light grey.
   ============================================================ */

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

/* ---- Accessibility floor ---- */
.skip-link {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
  background: var(--ink-9); color: #fff; text-decoration: none;
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: var(--ls-micro);
}
.skip-link:focus {
  width: auto; height: auto; margin: 0; overflow: visible; clip-path: none;
  padding: 0.9rem 1.4rem; left: 1rem; top: 1rem; z-index: 999;
}
:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--accent); outline-offset: 4px;
}

/* Bootstrap Reboot enables :root { scroll-behavior: smooth } under
   prefers-reduced-motion: no-preference. Nobody asked for it, it hijacks
   native scrolling, and it cannot be found by walking document.styleSheets
   because the jsDelivr sheet is cross-origin and cssRules throws. Reassert. */
:root { scroll-behavior: auto; }
section[id] { scroll-margin-top: 4rem; }
img, svg { max-width: 100%; }

/* ══════════ SHELL ══════════
   No max-width on sections. Bands run the full viewport; only the inner
   text column is constrained. */
.band { padding-block: var(--pad-section); }
.band--dark  { background: var(--ink-9); color: var(--band); }
.band--grey  { background: var(--band); }
.band--white { background: var(--paper); }

.band--dark h1, .band--dark h2, .band--dark h3 { color: #fff; }
/* --mid is 5.43:1 on the dark band, but only 2.47:1 on the light band, so it
   is allowed to carry text here and never there. */
.band--dark .eyebrow { color: var(--mid); }

.wrap { padding-inline: var(--gutter); }
.col  { max-width: var(--measure); }
.col--wide { max-width: 90rem; margin-inline: auto; }

/* ---- Micro-label. Nav, buttons, eyebrows. ---- */
.eyebrow {
  display: block;
  font-size: var(--t-micro);
  font-weight: var(--w-body);
  text-transform: uppercase;
  letter-spacing: var(--ls-micro);
  color: var(--meta);
  margin: 0 0 1.75rem;
}
.eyebrow--accent { color: var(--accent); }

.lede {
  font-size: clamp(1.05rem, 1rem + 0.4vw, 1.25rem);
  font-weight: var(--w-light);
  line-height: 1.55;
  color: var(--ink);
  max-width: var(--measure);
}
.band--dark .lede { color: var(--band); }

/* ---- Buttons: transparent, square, micro-label type. ---- */
.btn-line {
  display: inline-flex; align-items: center; gap: 0.7rem;
  padding: 1rem 0;
  background: transparent; border: 0;
  border-bottom: 1px solid var(--ink-9);
  color: var(--ink-9);
  font-size: var(--t-micro); font-weight: var(--w-body);
  text-transform: uppercase; letter-spacing: var(--ls-micro);
  text-decoration: none; border-radius: 0;
  transition: color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}
.btn-line:hover { color: var(--accent); border-bottom-color: var(--accent); }
.band--dark .btn-line { color: #fff; border-bottom-color: rgba(255,255,255,.5); }
/* --accent is 2.82:1 on the dark band, so the hover state there resolves to
   white rather than colour. Colour is a light-ground device on this site. */
.band--dark .btn-line:hover { color: #fff; border-bottom-color: #fff; }

/* ══════════ NAV ══════════ */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem;
  padding: 1.5rem var(--gutter);
  mix-blend-mode: difference;
}
.nav a { color: #fff; text-decoration: none; }
.nav-mark {
  font-size: var(--t-micro); text-transform: uppercase;
  letter-spacing: var(--ls-micro); font-weight: var(--w-body);
}
/* Visible at every width. Below 48em the mark and the links share the bar
   on two rows rather than the links disappearing: a phone visitor with no
   menu at all could not reach Experience or Contact without scrolling the
   whole page. */
.nav-list { display: flex; flex-wrap: wrap; gap: 0.25rem 1.25rem; list-style: none; margin: 0; padding: 0; }
@media (min-width: 48em) { .nav-list { gap: 2.25rem; } }
@media (max-width: 47.98em) {
  /* Solid on phones. The see-through bar works on a wide screen, where it
     sits over open space; on a phone it is two rows tall and page text
     scrolled underneath collided with the name and the links. */
  .nav { flex-wrap: wrap; row-gap: 0.25rem; padding: 0.9rem var(--gutter);
         background: var(--ink-9); mix-blend-mode: normal; }
}
/* A menu jump lands the section heading below the fixed bar, not under it. */
main [id] { scroll-margin-top: 6rem; }
.nav-list a {
  font-size: var(--t-micro); text-transform: uppercase;
  letter-spacing: var(--ls-micro); padding-block: 0.5rem;
  opacity: .75; transition: opacity var(--dur-fast) ease;
}
/* Attribute presence, not a specific value. app.js sets "true" for the
   scroll spy on the index; a hand authored page sets "page", which is the
   correct ARIA value for the current document. Matching only "true" meant
   the highlight never fired on contact.html. */
.nav-list a:hover, .nav-list a[aria-current] { opacity: 1; }

/* ══════════ HERO ══════════ */
.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  align-content: end;
  padding: var(--gutter);
  /* Clear of the fixed bar however long the headline runs. Without this a
     long h1 grew upward underneath the name on a phone. */
  padding-top: calc(var(--gutter) + 6rem);
  padding-bottom: clamp(2rem, 1rem + 4vw, 4rem);
  overflow: hidden;
  background: var(--ink-9);
}
.hero-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  display: block;
}
/* Scrim: exactly the specified 0.30 -> 0.50, and it holds without compromise.

   It only holds because the photograph was made for the job rather than
   found: a purpose-generated low-key twilight tower, then graded to the same
   family as the rest of the imagery. Measured on the final asset by sampling
   it to a canvas and blending the overlay by hand — axe cannot do this, it
   returns "incomplete" over a background image. Worst-case white anywhere in
   the frame:
       0.20 -> 4.07 (AA large)    0.26 -> 4.65 (AA body)    0.30 -> 5.09

   Earlier iterations needed 0.56 and 0.66 to clear the same bar, because the
   source photographs were bright. Fixing the input, not cranking the overlay,
   is what let the brief's own numbers survive. */
.hero::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to bottom,
    rgba(0,0,0,.30) 0%,
    rgba(0,0,0,.36) 45%,
    rgba(0,0,0,.50) 100%);
}
.hero-inner { position: relative; z-index: 2; width: 100%; }
.hero h1 { color: #fff; max-width: 18ch; }
.hero-sub {
  margin-top: 1.75rem; max-width: 46ch;
  color: rgba(255,255,255,.88);
  font-weight: var(--w-light);
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.15rem);
}
.hero-foot {
  position: relative; z-index: 2;
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 1.5rem; margin-top: clamp(2.5rem, 1rem + 6vw, 5rem);
}
.hero-scroll {
  font-size: var(--t-micro); text-transform: uppercase;
  letter-spacing: var(--ls-micro); color: rgba(255,255,255,.85);
  display: inline-flex; align-items: center; gap: 0.6rem;
  text-decoration: none;
}

/* SIGNATURE 1 of 2. Bodoni Moda appears exactly twice on this page. */
.hero-mark {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.75rem, 1rem + 5vw, 5.5rem);
  line-height: 0.9;
  color: rgba(255,255,255,.94);
  text-align: right;
  margin: 0;
}
@media (max-width: 47.98em) {
  .hero-foot { flex-direction: column; align-items: flex-start; }
  .hero-mark { text-align: left; }
}

/* ══════════ SECTION HEAD ══════════ */
.head { margin-bottom: clamp(2.5rem, 1.5rem + 3vw, 4.5rem); }
.head h2 { max-width: 20ch; }
.head .lede { margin-top: 1.5rem; }

/* ══════════ WORK ══════════ */
.work { border-top: 1px solid var(--rule); }
.band--dark .work { border-top-color: var(--rule-dark); }
.work-item {
  display: grid; gap: 0.75rem 3rem;
  padding-block: clamp(2rem, 1.2rem + 2.5vw, 3.25rem);
  border-bottom: 1px solid var(--rule);
  align-items: start;
}
.band--dark .work-item { border-bottom-color: var(--rule-dark); }
@media (min-width: 62em) {
  .work-item { grid-template-columns: 5rem minmax(0, 22ch) minmax(0, 1fr); align-items: baseline; }
}
.work-idx {
  font-size: var(--t-micro); letter-spacing: var(--ls-micro);
  color: var(--meta); font-variant-numeric: tabular-nums;
}
.band--dark .work-idx { color: var(--mid); }
.work-item h3 { color: var(--ink-9); }
.band--dark .work-item h3 { color: #fff; }
.work-body { color: var(--ink); }
.band--dark .work-body { color: var(--band); }
.work-body p + p { margin-top: 0.9rem; }
.work-tag {
  display: block; margin-top: 1.1rem;
  font-size: var(--t-micro); text-transform: uppercase;
  letter-spacing: var(--ls-micro); color: var(--meta);
}
.band--dark .work-tag { color: var(--mid); }

/* ══════════ FULL-BLEED MEDIA ══════════ */
.plate { margin: 0; position: relative; }
.plate img { width: 100%; height: auto; display: block; }
.plate--tall { aspect-ratio: 21 / 9; }
.plate--tall img { height: 100%; object-fit: cover; }
@media (max-width: 47.98em) { .plate--tall { aspect-ratio: 4 / 3; } }
.plate figcaption {
  padding: 0.9rem var(--gutter) 0;
  font-size: var(--t-micro); text-transform: uppercase;
  letter-spacing: var(--ls-micro); color: var(--meta);
  display: flex; flex-wrap: wrap; gap: 0.4rem 1.5rem; justify-content: space-between;
}
.plate figcaption a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.plate figcaption a:hover { color: var(--accent); }

/* ══════════ PLATE OVERLAY ══════════
   The full-bleed plate used to be a mute picture between two sections. It now
   carries a line and a CTA, which turns a scroll-past into a second entry
   point to the services.

   The scrim is a left weighted horizontal ramp with a flat plateau under the
   text, same device as the service hero: constant alpha under type makes the
   contrast computable rather than guessed, and the right of the photograph is
   left almost untouched. */
.plate--cta::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(to right,
      rgba(0,0,0,.68) 0%, rgba(0,0,0,.66) 48%,
      rgba(0,0,0,.28) 78%, rgba(0,0,0,.16) 100%),
    linear-gradient(to bottom, rgba(0,0,0,.20) 0%, rgba(0,0,0,0) 45%);
}
.plate-in {
  position: absolute; inset: 0; z-index: 1;
  display: flex; flex-direction: column; justify-content: center;
  gap: 1.5rem;
  padding: var(--gutter);
  max-width: 42rem;
}
.plate-in p {
  color: #fff;
  font-size: clamp(1.35rem, 0.9rem + 2.6vw, 3.9rem);
  font-weight: var(--w-thin);
  line-height: 1.15;
  letter-spacing: var(--ls-head);
  text-wrap: balance;
}
.plate-in .cta { margin-top: 0; }

/* The 21/9 crop is far too letterboxed for stacked text on a phone, and the
   CTA would sit on top of the line. Give it height and breathing room. */
@media (max-width: 47.98em) {
  .plate--cta.plate--tall { aspect-ratio: 4 / 5; }
  .plate-in { justify-content: flex-end; gap: 1.25rem; padding-bottom: 2.5rem; }
}
@media (forced-colors: active) {
  .plate--cta::after { display: none; }
}
@media print {
  .plate--cta::after { display: none; }
  .plate-in { position: static; padding: 0; }
  .plate-in p { color: #000 !important; }
}

/* ══════════ CAPABILITIES ══════════ */
.grid-2 { display: grid; gap: 0; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 48em) { .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 4rem; } }
.cap { padding-block: clamp(1.75rem, 1rem + 2vw, 2.75rem); border-top: 1px solid var(--rule); }
.band--dark .cap { border-top-color: var(--rule-dark); }
.cap h3 { margin-bottom: 0.9rem; }
.cap p { color: var(--ink); }
.band--dark .cap p { color: var(--band); }
.cap-runs {
  display: block; margin-top: 1rem;
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: var(--ls-micro);
  color: var(--meta); line-height: 1.7;
}
.band--dark .cap-runs { color: var(--mid); }
.cap-runs b { color: var(--accent); font-weight: var(--w-body); }
/* --accent measures 2.82:1 on the dark band, under AA at every size, so on
   dark the key reverts to the AA-safe grey. */
.band--dark .cap-runs b { color: var(--band); }

/* ══════════ STACK ══════════ */
.stack-row {
  display: grid; gap: 0.75rem 3rem;
  padding-block: 1.5rem; border-top: 1px solid var(--rule);
  align-items: baseline;
}
.band--dark .stack-row { border-top-color: var(--rule-dark); }
@media (min-width: 48em) { .stack-row { grid-template-columns: 16rem minmax(0, 1fr); } }
.stack-row:last-child { border-bottom: 1px solid var(--rule); }
.band--dark .stack-row:last-child { border-bottom-color: var(--rule-dark); }
.stack-k {
  font-size: var(--t-micro); text-transform: uppercase;
  letter-spacing: var(--ls-micro); color: var(--meta);
}
.band--dark .stack-k { color: var(--mid); }
.stack-v { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.4rem 1.5rem; }
.stack-v li { font-weight: var(--w-light); color: var(--ink); }
.band--dark .stack-v li { color: #fff; }

/* ══════════ SPLIT ══════════ */
.split { display: grid; gap: 3rem; grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (min-width: 62em) { .split { grid-template-columns: 22rem minmax(0, 1fr); gap: 5rem; } }
.portrait { margin: 0; }
.portrait img {
  width: 100%; height: auto; display: block;
  aspect-ratio: 4/5; object-fit: cover; object-position: center 22%;
}
.portrait figcaption {
  margin-top: 1rem; font-size: var(--t-micro); text-transform: uppercase;
  letter-spacing: var(--ls-micro); color: var(--meta); line-height: 1.9;
}

.cv { list-style: none; margin: 0; padding: 0; }
.cv li {
  display: grid; gap: 0.4rem 3rem; padding-block: 1.6rem;
  border-top: 1px solid var(--rule);
}
.cv li:last-child { border-bottom: 1px solid var(--rule); }
@media (min-width: 48em) { .cv li { grid-template-columns: 9rem minmax(0, 1fr); } }
.cv-when { font-size: var(--t-micro); text-transform: uppercase; letter-spacing: var(--ls-micro); color: var(--meta); }
.cv h3 { font-size: 1.25rem; margin-bottom: 0.5rem; }

/* ══════════ INTENT ══════════ */
/* ══════════ CONTACT ══════════ */
/* SIGNATURE 2 of 2. */
.contact-mark {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(2.5rem, 1rem + 7vw, 6rem);
  line-height: 0.95; color: var(--ink-9); margin: 0 0 2.5rem;
}
.band--dark .contact-mark { color: #fff; }

/* Social glyphs are Lucide only — one icon set, no brand-mark mixing. Indeed
   has no Lucide brand glyph, so it uses Lucide's briefcase rather than
   importing a second set for a single icon. */
.soc-i { width: 1.25rem; height: 1.25rem; flex: none; opacity: .85; }


/* ══════════ MOTION ══════════
   Fade plus a subtle rise, 700ms ease-out, staggered.
   Elements START VISIBLE. JS adds .is-armed only once it has confirmed it
   can animate them back, so a script failure degrades to a readable page
   rather than a blank one. */
.reveal { opacity: 1; }
.reveal.is-armed { opacity: 0; transform: translateY(20px); }
.reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity var(--dur-reveal) var(--ease-out),
              transform var(--dur-reveal) var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
  .reveal, .reveal.is-armed { opacity: 1 !important; transform: none !important; }
}

/* ══════════ FORCED COLOURS ══════════ */
@media (forced-colors: active) {
  .hero::after { display: none; }
  .btn-line, .work-item, .cap, .stack-row, .cv li { border-color: CanvasText; }
  .foot-cta { border-color: CanvasText; }
  /* A gradient over a photo is invisible to forced-colours, so the panel text
     would sit on unmediated image. Drop the art and let the system colours
     carry the panel. */
  .svc img { display: none; }
  .svc-scrim { background: none; }
  .svc, .cta-primary, .cta-secondary { border-color: CanvasText; }
  .foot-soc .is-placeholder { opacity: 1; }
}

/* ══════════ PRINT ══════════ */
@media print {
  .reveal, .reveal.is-armed { opacity: 1 !important; transform: none !important; }
  .nav, .hero-scroll, .plate, .hero-img { display: none; }
  .hero { min-height: auto; padding-block: 2rem; background: none; }
  .hero::after { display: none; }
  .hero h1, .hero-sub, .hero-mark { color: #000 !important; }
  .band { padding-block: 1.5rem; background: none !important; color: #000 !important; }
  .band--dark * { color: #000 !important; }
  .work-item, .cap, .cv li { break-inside: avoid; }
  h1, h2, h3 { break-after: avoid; }
  .services { display: none; }
  .cta-primary, .cta-secondary { border: 0; padding: 0; color: #000 !important; }
  .foot-soc a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.7em; }
}

/* ══════════ SERVICES — full-bleed three-panel split ══════════
   Edge to edge, no container, no gaps. Each panel is one link: the whole
   thing is the target, so there is no small tap area to miss. On desktop the
   hovered panel widens and the others yield, which is the device from the
   reference — done with grid-template-columns transitions rather than
   transforms so nothing overflows the viewport. */
.services {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  background: var(--ink-9);
}
@media (min-width: 48em) {
  .services {
    grid-template-columns: 1fr 1fr 1fr;
    transition: grid-template-columns 600ms var(--ease-out);
  }
  /* Guarded: without :has() the yield rule would fire alone and shrink all
     three panels with nothing widening to take the space. */
  @supports selector(:has(*)) {
    .services:hover { grid-template-columns: 0.86fr 0.86fr 0.86fr; }
    .services:has(.svc:nth-child(1):hover) { grid-template-columns: 1.4fr 0.8fr 0.8fr; }
    .services:has(.svc:nth-child(2):hover) { grid-template-columns: 0.8fr 1.4fr 0.8fr; }
    .services:has(.svc:nth-child(3):hover) { grid-template-columns: 0.8fr 0.8fr 1.4fr; }
  }
}

.svc {
  position: relative;
  display: block;
  overflow: hidden;
  min-height: 62vh;
  text-decoration: none;
  color: #fff;
  border-right: 1px solid rgba(255,255,255,.10);
}
.svc:last-child { border-right: 0; }
@media (min-width: 48em) { .svc { min-height: 82vh; } }

.svc img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 600ms var(--ease-out);
}
.svc:hover img { transform: scale(1.04); }
/* NOTE, because this looks like a place to reach for object-position and it
   will not work: the panels are 768x1024 portraits at aspect 0.75. A widened
   panel is about 665x738, aspect 0.90, so `cover` scales to fit the WIDTH and
   the overflow is vertical. A horizontal object-position has no effect there
   at all. The brokerage frame had a blank plaster wall down its left side that
   filled a third of the widened panel, and the only real fix was cropping it
   out of the source file. Left here as a warning. */

/* Scrim is its own element rather than a pseudo, so the panel can host both
   it and the label without stacking-order guesswork. Measured: white on the
   generated panel art needs ~0.30 to clear AA at this text size. */
.svc-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(to bottom,
    rgba(0,0,0,.28) 0%, rgba(0,0,0,.34) 55%, rgba(0,0,0,.66) 100%);
  transition: background 600ms var(--ease-out);
}
.svc:hover .svc-scrim {
  background: linear-gradient(to bottom,
    rgba(0,0,0,.34) 0%, rgba(0,0,0,.42) 55%, rgba(0,0,0,.74) 100%);
}

.svc-label {
  position: absolute; left: var(--gutter); right: 3.5rem; bottom: var(--gutter);
  display: grid; gap: 0.45rem;
}
.svc-name {
  /* Ceiling raised from 1.6rem: these sit over full bleed art, and on a
     1440px+ screen the old cap read as a caption rather than a heading. */
  font-size: clamp(1.15rem, 0.85rem + 1.15vw, 2.35rem);
  font-weight: var(--w-light);
  letter-spacing: 0.01em;
  line-height: 1.15;
}
/* The sub-line is held back until hover on pointer devices, and always shown
   where hover does not exist. */
.svc-note {
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: var(--ls-micro);
  color: rgba(255,255,255,.82);
}
@media (hover: hover) and (min-width: 48em) {
  .svc-note { opacity: 0; transform: translateY(6px); transition: opacity 500ms var(--ease-out), transform 500ms var(--ease-out); }
  .svc:hover .svc-note, .svc:focus-visible .svc-note { opacity: 1; transform: none; }
}

.svc-plus {
  position: absolute; right: var(--gutter); bottom: var(--gutter);
  width: 1.5rem; height: 1.5rem;
  display: grid; place-items: center;
  transition: transform 500ms var(--ease-out);
}
.svc-plus svg { width: 100%; height: 100%; }
.svc:hover .svc-plus { transform: rotate(90deg); }
.svc:focus-visible { outline: 2px solid #fff; outline-offset: -6px; }

/* ══════════ CTA ══════════ */
.cta { display: flex; flex-wrap: wrap; gap: 1rem 2.5rem; align-items: center; margin-top: 3rem; }
.cta-primary {
  display: inline-flex; align-items: center; gap: 0.9rem;
  padding: 1.15rem 2rem;
  border: 1px solid #fff; border-radius: 0;
  background: transparent; color: #fff;
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: var(--ls-micro);
  text-decoration: none;
  transition: background 260ms ease, color 260ms ease, border-color 260ms ease;
}
.cta-primary:hover { background: #fff; color: var(--ink-9); }
.band--white .cta-primary, .band--grey .cta-primary { border-color: var(--ink-9); color: var(--ink-9); }
.band--white .cta-primary:hover, .band--grey .cta-primary:hover { background: var(--ink-9); color: #fff; }

.cta-secondary {
  display: inline-flex; align-items: center; gap: 0.7rem;
  color: var(--mid); text-decoration: none;
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: var(--ls-micro);
  border-bottom: 1px solid transparent; padding-block: 0.4rem;
  transition: color 260ms ease, border-color 260ms ease;
}
a.cta-secondary:hover { color: #fff; border-bottom-color: rgba(255,255,255,.4); }
span.cta-secondary[data-placeholder] { font-style: italic; cursor: default; }

/* ══════════ FOOT — one horizontal line ══════════
   Name left, social centre, copyright right; stacks centred on narrow
   screens. The 44px tap targets set the bar's height, so the block padding
   is almost nothing: this should read as a seam under the page, not as
   another section. */
.foot {
  /* Two lanes: the social marks on their own row, then one line carrying the
     name, the links and the copyright. */
  display: grid; justify-items: center;
  gap: 1rem;
  padding: 1.5rem var(--gutter);
  background: var(--ink-10);
  border-top: 1px solid var(--rule-dark);
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: var(--ls-micro);
  color: var(--mid);   /* 6.20:1 on --ink-10 */
}

/* 1fr auto 1fr, not space-between: space-between only centres the middle item
   when the two flanking items happen to match in width, so the links drifted
   as the name and the copyright changed. */
.foot-line {
  width: 100%;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  gap: 0.5rem 2rem;
}
.foot p { margin: 0; }
.foot-line .foot-meta { justify-self: end; }

.foot-soc {
  display: flex; align-items: center; justify-content: center; gap: 0.1rem;
  list-style: none; margin: 0; padding: 0;
}
/* :not(.foot-cta) is load bearing. `.foot-soc a` is specificity 0,1,1 and
   beats a bare `.foot-cta` at 0,1,0, so without the exclusion the Contact
   button inherited both the grey text (1.92:1 on the accent fill, which axe
   caught) and the 44px square box, which crushed its label. */
.foot-soc a:not(.foot-cta),
.foot-soc .is-placeholder {
  display: grid; place-items: center;
  width: 2.75rem; height: 2.75rem;   /* 44px, the WCAG 2.5.8 floor exactly */
  color: var(--mid);
  transition: color 240ms ease;
}
/* The glyph runs to 28px inside that 44px box. These are the only icons on
   the site that are the click target rather than a label beside one, so
   they carry more weight than the 20px marks used inline. */
.foot-soc .soc-i { width: 1.75rem; height: 1.75rem; opacity: 1; }
.foot-soc a { text-decoration: none; }
.foot-soc a:not(.foot-cta):hover { color: #fff; }

/* Unfilled profiles are spans, not links: nothing to focus, nothing to
   follow, and they read as dimmer marks that are plainly not yet live. */
.foot-soc .is-placeholder {
  /* .38 measured 1.91:1 against the footer ground, under 1.4.11's 3:1 for
     a mark that carries a name. .62 lands at 3.09:1 and still reads dimmer
     than the live icons beside it. */
  color: var(--mid); opacity: .62;
}

/* The one highlighted control down here. Filled rather than outlined so it
   is unmistakably the button among the marks. White on --accent is 5.79:1;
   --accent against the footer ground is 3.22:1, clearing 1.4.11 for the
   control's own boundary. */
.foot-soc .foot-cta {
  display: inline-flex; align-items: center; gap: 0.5rem;
  margin-left: 0.6rem;
  min-height: 2.75rem; padding: 0 1.35rem;
  background: var(--accent); color: #fff;
  text-decoration: none; border: 1px solid var(--accent);
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: var(--ls-micro);
  transition: background 240ms ease, color 240ms ease, border-color 240ms ease;
}
.foot-soc .foot-cta:hover { background: #fff; color: var(--ink-10); border-color: #fff; }

@media (max-width: 47.98em) {
  .foot { padding-block: 1.75rem; }
  .foot-line { grid-template-columns: 1fr; justify-items: center; text-align: center; gap: 0.9rem; }
  .foot-line .foot-meta { justify-self: center; }
  .foot-legal ul { justify-content: center; }
}

/* ══════════ CENTRED CTA ══════════
   Used by the contact band, where the button is the whole point of the
   section rather than one option beside a paragraph. */
.cta--center { justify-content: center; margin-top: 4rem; padding-block: 1rem; }
.head--center { text-align: center; }
.head--center .lede { margin-inline: auto; }
.head--center .contact-mark { text-align: center; }

/* ══════════ LEGAL ROW ══════════
   Sits under the footer as a quieter second line. Separate from .foot on
   purpose: the footer is identity and social, this is obligation, and
   collapsing them into one bar made the bar tall again. */
.foot-legal { justify-self: center; }
.foot-legal ul {
  display: flex; flex-wrap: wrap; gap: 0.15rem 1.75rem;
  list-style: none; margin: 0; padding: 0;
  justify-content: center;
}
.foot-legal a {
  display: inline-flex; align-items: center;
  min-height: 2rem;
  color: var(--mid);            /* 6.20:1 on --ink-10 */
  text-decoration: none;
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: var(--ls-micro);
  border-bottom: 1px solid transparent;
  transition: color 240ms ease, border-color 240ms ease;
}
.foot-legal a:hover { color: #fff; border-bottom-color: rgba(255,255,255,.4); }

/* ══════════ LEGAL PAGES ══════════ */
.col--narrow { max-width: 48rem; margin-inline: auto; }
/* A legal page has no hero, so the fixed nav would sit on the h1. */
.nav--solid { position: static; background: var(--ink-9); mix-blend-mode: normal; }
.nav--solid .nav-mark, .nav--solid .nav-list a { color: #fff; }
.legal-h1 { font-size: clamp(2rem, 1.4rem + 2.4vw, 3.25rem); }
.legal-meta {
  margin-top: 1rem; color: var(--meta);
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: var(--ls-micro);
}
.legal-warn {
  margin-bottom: 3rem; padding: 1rem 1.25rem;
  border: 1px dashed var(--mid); color: var(--meta);
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: var(--ls-micro);
}
.legal-body h2 {
  font-size: var(--t-h3); font-weight: var(--w-light);
  margin: 2.75rem 0 0.75rem; letter-spacing: 0;
}
.legal-body h2:first-child { margin-top: 0; }
.legal-body p { max-width: var(--measure); }

@media (forced-colors: active) {
  .legal-warn { border-color: CanvasText; }
}

/* The link back to the page you are already on. Marked rather than removed:
   the row should stay the same shape on every page so it does not reflow as
   you move between them. */
.foot-legal a[aria-current="page"] { color: #fff; cursor: default; }
.foot-legal a[aria-current="page"]:hover { border-bottom-color: transparent; }

/* Was an inline style attribute. Moved here because the live site's CSP
   forbids inline styles. */
ol.work { list-style: none; margin: 0; padding: 0; }

/* ══════════ SERVICES OFFERED / EXPERIENCE ══════════ */
.grid-3 { display: grid; gap: 3rem; }
@media (min-width: 62em) { .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 3.5rem; } }
.cap-link { display: inline-block; margin-top: 1.25rem; }
.platforms { margin: clamp(2.5rem, 1.5rem + 3vw, 4rem) 0 0; color: var(--ink); max-width: 72ch; }
.platforms b { font-weight: var(--w-body); display: block; font-size: var(--t-micro);
  text-transform: uppercase; letter-spacing: var(--ls-micro); color: var(--meta); margin-bottom: 0.5rem; }
.thanks { min-height: 60vh; display: grid; align-content: center; }
