/* =====================================================================
   Colum Colfer Architect
   1. Tokens      5. Curtain menu   9.  Inner pages    13. Photos
   2. Base        6. Intro          10. Services/steps 14. Frames
   3. Layout      7. Panels         11. Entries/forms  15. Motion
   4. Masthead    8. Statements     12. Footer         16. Breakpoints
   ===================================================================== */

/* 0. Fonts ----------------------------------------------------------- */
/* TeX Gyre Heros (GUST e-foundry, GFL) shipped with the site, so every
   visitor sees it. Regular and Bold cover the weights in use; lighter and
   heavier weights snap to the nearest of the two. */
@font-face {
  font-family: "TeX Gyre Heros";
  src: url("../fonts/texgyreheros-regular.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "TeX Gyre Heros";
  src: url("../fonts/texgyreheros-bold.otf") format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* 1. Tokens ---------------------------------------------------------- */
:root {
  color-scheme: light only;

  /* Grey paper, not white â it is most of why the page reads as considered
     rather than empty. One brand colour, #163435, does ink and dark ground. */
  --paper:     #c9cdcc;
  --paper-2:   #d6d9d8;
  --card:      #dfe2e1;
  --ink:       #163435;  /* 8.2:1 on paper */
  --ink-2:     #33504f;  /* 5.4:1 on paper */
  --ink-soft:  #3a5756;  /* 4.8:1 on paper */
  --dark:      #163435;
  --line:      rgba(22, 52, 53, 0.28);
  --line-soft: rgba(22, 52, 53, 0.14);
  --accent:    #163435;
  --scrim:     22, 52, 53;
  --title:     #808080;  /* all titles, including the wordmark */

  --font: "TeX Gyre Heros", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --step--1: clamp(0.76rem, 0.74rem + 0.1vw, 0.82rem);
  --step-0:  clamp(1rem, 0.97rem + 0.16vw, 1.09rem);
  --step-1:  clamp(1.15rem, 1.07rem + 0.36vw, 1.4rem);
  --step-2:  clamp(1.45rem, 1.28rem + 0.82vw, 2.05rem);
  --step-3:  clamp(1.9rem, 1.5rem + 1.9vw, 3.2rem);
  --step-4:  clamp(2.5rem, 1.5rem + 4.6vw, 5.4rem);

  /* One spacing token and one wordmark token. The masthead height and the
     intro's landing position are both calculated off the wordmark, so the
     intro lands exactly on the real brand and becomes it. */
  --pad:        clamp(1.1rem, 3vw, 2rem);
  --wordmark:   clamp(1.5rem, 3.4vw, 2.6rem);
  /* the size the name announces itself at, before it shrinks to --wordmark.
     Capped against the viewport so the full lockup never overflows. */
  --intro-size: clamp(2.2rem, 6.2vw, 5.2rem);
  --brand-top:  calc(var(--pad) * 0.9);
  --mast-h:     calc(var(--wordmark) * 1.25 + var(--pad) * 1.8);

  --gap:     clamp(1.25rem, 0.9rem + 1.5vw, 2.25rem);
  --section: clamp(3.75rem, 2.5rem + 5vw, 7.5rem);
  --wrap:    76rem;
  --ease:    cubic-bezier(0.65, 0, 0.25, 1);
}

/* 2. Base ------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink-2);
  font: 400 var(--step-0)/1.6 var(--font);
  font-stretch: 100%; /* Swis721 BT at width factor 1.0 â no condensing or expansion */
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
/* the page holds its breath until the script says go */
html.js body { opacity: 0; transition: opacity 0.4s; }
html.js body.is-ready { opacity: 1; }

h1, h2, h3, h4 {
  margin: 0 0 0.55em;
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.022em;
  color: var(--title);
  text-wrap: balance;
}

p { margin: 0 0 1.1em; max-width: 64ch; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 0.25em; }
/* form controls and code don't inherit the page font by default â force it,
   so every last element renders in TeX Gyre Heros */
button, input, select, textarea { font: inherit; }
code, kbd, samp, pre { font-family: var(--font); }
strong { font-weight: 600; }
img { max-width: 100%; height: auto; display: block; }
ul, ol { margin: 0; padding: 0; list-style: none; }
address { font-style: normal; }

:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

.visually-hidden, .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 {
  position: absolute; top: -100%; left: 1rem; z-index: 300;
  padding: 0.75rem 1.1rem; background: var(--dark); color: #fff; text-decoration: none;
}
.skip:focus { top: 1rem; }

/* micro-label: the tracked uppercase that carries most of the small type */
.micro {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* 3. Layout ----------------------------------------------------------- */
.wrap { width: min(100% - (var(--pad) * 2), var(--wrap)); margin-inline: auto; }
.section { padding-block: var(--section); }
.section--tint { background: var(--paper-2); }
/* a section that follows straight on from a page title, so the two do not
   stack their padding into a gap */
.section--flush { padding-top: 0; }

.mark {
  display: block;
  width: clamp(2.75rem, 2rem + 2.4vw, 4.5rem);
  height: 3px;
  margin-bottom: clamp(1.1rem, 0.9rem + 0.6vw, 1.8rem);
  background: var(--ink);
}
.mark--light { background: #fff; }

.section-head { margin-bottom: clamp(2rem, 1.2rem + 2.4vw, 3.5rem); }
.section-title { font-size: var(--step-3); margin: 0; }
.section-head .section-title + p { margin-top: 1rem; }
.lede { font-size: var(--step-1); font-weight: 400; line-height: 1.5; color: var(--ink-2); }

.link-arrow {
  display: inline-flex; align-items: center; gap: 0.5em;
  font-size: var(--step--1); font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase;
  text-decoration: none;
  border-bottom: 1px solid var(--line);
  padding-bottom: 0.35em;
  transition: border-color 0.3s var(--ease), gap 0.3s var(--ease);
}
.link-arrow::after { content: "\2192"; }
.link-arrow:hover { border-color: var(--ink); gap: 0.95em; }

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 3.1rem; padding: 0 1.9rem;
  border: 2px solid var(--ink);
  font-size: var(--step--1); font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
  text-decoration: none; cursor: pointer;
  transition: background-color 0.3s var(--ease), color 0.3s var(--ease), border-color 0.3s var(--ease);
}
.btn--solid { background: var(--ink); border-color: var(--ink); color: #fff; }
.btn--solid:hover { background: transparent; color: var(--ink); }
.btn--ghost { background: transparent; color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: #fff; }
.btn--light { background: #fff; border-color: #fff; color: var(--ink); }
.btn--light:hover { background: transparent; color: #fff; border-color: #fff; }
.btn--outline-light { background: transparent; border-color: rgba(255, 255, 255, 0.65); color: #fff; }
.btn--outline-light:hover { background: #fff; border-color: #fff; color: var(--ink); }

/* 4. Masthead ---------------------------------------------------------- */
.masthead {
  position: fixed; inset: 0 0 auto;
  z-index: 100;
  height: var(--mast-h);
  background: var(--dark);
  overflow: hidden;
  transition: transform 0.35s var(--ease), background-color 0.35s var(--ease);
}
body.mast-hidden:not(.menu-open) .masthead { transform: translateY(-102%); }

.brand {
  position: absolute;
  left: var(--pad);
  top: var(--brand-top);
  display: block;
  font-size: var(--wordmark);
  line-height: 1.25;
  letter-spacing: -0.02em;
  text-decoration: none;
  text-transform: lowercase;
  white-space: nowrap;
  color: var(--title);
}
.brand b { font-weight: 400; }
.brand span {
  font-weight: 800; opacity: 0.75;
  /* vertical dividing line between the name and the role */
  border-left: 4px solid currentColor;
  padding-left: 0.5em;
  margin-left: 0.15em;
}
.page-home .brand, body.menu-open .brand { color: var(--title); }

.menu-toggle {
  position: fixed;
  right: var(--pad);
  top: var(--brand-top);
  z-index: 110;
  display: grid; place-items: center;
  width: 2.6rem; height: 2.6rem;
  padding: 0; border: 0; background: none;
  color: #fff; /* the burger sits on the teal masthead everywhere */
  cursor: pointer;
}
.page-home .menu-toggle, body.menu-open .menu-toggle { color: #fff; }
.burger, .burger::before, .burger::after {
  display: block; width: 1.6rem; height: 2px;
  background: currentColor;
  transition: transform 0.35s var(--ease), opacity 0.2s linear;
}
.burger { position: relative; }
.burger::before, .burger::after { content: ""; position: absolute; left: 0; }
.burger::before { top: -6px; }
.burger::after  { top: 6px; }
body.menu-open .burger { background: transparent; }
body.menu-open .burger::before { transform: translateY(6px) rotate(45deg); }
body.menu-open .burger::after  { transform: translateY(-6px) rotate(-45deg); }

/* 5. Overlay menu ------------------------------------------------------ */
/* Modelled on the Green Sheep Collective mobile nav: a short beat after the
   tap, the whole teal sheet with the page options fades in fast (100ms
   linear), and fades back out the same way on close. No sliding panels. */
.menu {
  position: fixed; inset: 0;
  z-index: 90;
  overflow: hidden;
  display: flex; flex-direction: column;
  background: var(--dark);
  opacity: 0;
  pointer-events: none;
  transition: opacity 100ms linear 100ms;
}
.menu[hidden] { display: none; }
.menu.is-open { opacity: 1; pointer-events: auto; }

.menu nav { height: 100%; }
.menu-list {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  height: 100%;
  gap: 1rem;
}
.menu-list a {
  color: var(--title);
  -webkit-text-stroke: 1.5px var(--title);
  font-weight: 600;
  font-size: clamp(1.3rem, 4.2vw, 2.5rem);
  line-height: 1.2;
  letter-spacing: 0.22em;
  text-transform: lowercase;
  text-decoration: none;
  transition: color 0.3s var(--ease);
}
.menu-list a:hover,
.menu-list a:focus-visible,
.menu-list a[aria-current="page"] { color: transparent; }
/* on a phone the links get real presence */
@media (max-width: 48em) {
  .menu-list a { font-size: 3rem; }
}

/* 6. Intro ------------------------------------------------------------- */
/* Three beats: the whole lockup wipes in large as one continuous motion,
   shrinks into the corner, then the hero photograph arrives.
   The mark ends at --wordmark / --pad / --brand-top, which is exactly where
   .brand sits, so it lands on the real brand instead of cross-fading with it. */
.intro { display: none; }
html.js .page-home .intro {
  display: block;
  position: fixed; inset: 0;
  z-index: 200;
  overflow: hidden;
  background: var(--dark);
  pointer-events: none;
  animation: intro-clear 0.4s var(--ease) 2.55s forwards;
}
.intro__mark {
  position: absolute;
  left: var(--pad);
  top: var(--brand-top);
  margin: 0;
  max-width: none;
  font-size: var(--intro-size);
  line-height: 1.25;
  letter-spacing: -0.02em;
  text-transform: lowercase;
  white-space: nowrap;
  color: var(--title);
  /* start dead-centre of the screen (the -50% is the mark's own box), then
     settle to translate(0,0), i.e. the corner position it is anchored to */
  transform: translate(calc(50vw - 50% - var(--pad)),
                       calc(50svh - var(--intro-size) * 0.625 - var(--brand-top)));
  /* one wipe across the whole lockup â a single easing curve sweeps through
     the name and straight on through the role, then the mark settles */
  clip-path: inset(0 100% 0 0);
  animation: intro-wipe 1.6s var(--ease) 0.15s forwards,
             intro-settle 0.6s var(--ease) 1.95s forwards;
}
.intro__name, .intro__role { display: inline-block; }
.intro__name { font-weight: 400; }
.intro__role {
  font-weight: 800; opacity: 0.75;
  /* same vertical dividing line as the masthead brand it lands on */
  border-left: 4px solid currentColor;
  padding-left: 0.5em;
  margin-left: 0.15em;
}

@keyframes intro-wipe   { to { clip-path: inset(0); } }
@keyframes intro-settle { to { font-size: var(--wordmark); transform: translate(0, 0); } }
@keyframes intro-clear  { to { background-color: transparent; visibility: hidden; } }

/* the carousel arrives once the wordmark has parked. This is on the carousel
   rather than on one image because the script inserts clones ahead of the
   first slide, so ":first-child" would land on a clone. */
html.js .page-home .carousel {
  opacity: 0;
  animation: hero-in 1s var(--ease) 2.6s forwards;
}
@keyframes hero-in { from { opacity: 0; transform: scale(1.04); } to { opacity: 1; transform: scale(1); } }

/* returning to home within the same visit: no intro, everything already there */
html.intro-skip .intro { display: none !important; }
html.intro-skip.js .page-home .carousel { opacity: 1; animation: none; }

/* 7. Panels ------------------------------------------------------------ */
.panels { display: block; }
.panel {
  position: relative;
  display: block;
  height: 100svh;
  scroll-snap-align: start;
  overflow: hidden;
}
.panel__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* a light scrim over the bottom only, so captions read without flattening the photo */
a.panel::after,
.panel--photo::after {
  content: "";
  position: absolute; inset: 55% 0 0;
  background: linear-gradient(rgba(var(--scrim), 0), rgba(var(--scrim), 0.62));
}
.panel__caption {
  position: absolute;
  left: var(--pad);
  right: calc(var(--pad) + 4rem);
  bottom: var(--pad);
  z-index: 1;
  display: flex; flex-wrap: wrap; gap: 0.5em 1.2em; align-items: baseline;
  color: #fff;
  font-size: var(--step--1);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.panel__caption strong { font-weight: 600; }
.panel__caption span { opacity: 0.75; }

/* 7b. Home carousel -----------------------------------------------------
   The slides are the panels above, laid in a row and slid sideways on a
   ten second timer. A clone of the last slide sits before the first and a
   clone of the first sits after the last, so the wrap is a slide like any
   other rather than a rewind through all six.

   All of this is scoped to html.js: without JS the panels stay in normal
   flow and the home page is a stack you scroll, which is a fair fallback. */
html.js .carousel { position: relative; height: 100svh; overflow: hidden; }
html.js .carousel-track {
  display: flex;
  height: 100%;
  will-change: transform;
  transition: transform 0.85s var(--ease);
}
html.js .carousel-track.is-jumping { transition: none; }
html.js .carousel-track > .panel { flex: 0 0 100%; height: 100%; }

/* the caption gives up its right-hand end to the controls */
.carousel .panel__caption { right: calc(var(--pad) + 9rem); }

.carousel-nav {
  position: absolute; z-index: 2;
  right: var(--pad); bottom: var(--pad);
  display: flex; align-items: center; gap: 0.35rem;
  color: #fff;
}
.carousel-step {
  width: 2.1rem; height: 2.1rem; padding: 0;
  display: grid; place-items: center;
  border: 0; background: none; color: inherit; cursor: pointer;
  font-size: 1.5rem; line-height: 1;
  opacity: 0.75; transition: opacity 0.3s var(--ease);
}
.carousel-step:hover { opacity: 1; }
.carousel-step:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.carousel-count {
  margin: 0; min-width: 3.2em; text-align: center;
  font-size: var(--step--1); font-weight: 600;
  letter-spacing: 0.16em; font-variant-numeric: tabular-nums;
}
/* 8. Statement panels --------------------------------------------------- */
.panel--statement {
  /* a photo panel is exactly one screen; a statement panel is at least one,
     and grows when its content needs the room (the six stages, on a phone) */
  height: auto;
  min-height: 100svh;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: clamp(1.5rem, 4vw, 2.5rem);
  padding: calc(var(--mast-h) + var(--pad)) var(--pad) calc(var(--pad) * 2.5);
  text-align: center;
  background: var(--dark);
  color: #fff;
}
.panel--statement.is-paper { background: var(--paper); color: var(--ink-2); }
.statement {
  max-width: 26ch;
  margin: 0;
  font-weight: 600;
  font-size: clamp(1.15rem, 2.6vw, 2rem);
  line-height: 1.45;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: inherit;
}
.statement--plain { letter-spacing: 0.02em; text-transform: none; font-weight: 400; max-width: 34ch; }
.statement-links {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 1rem clamp(1.2rem, 4vw, 2.2rem);
  max-width: 100%;
}
.statement-links a {
  font-size: var(--step--1); font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase;
  text-decoration: none;
  border-bottom: 1px solid rgba(255, 255, 255, 0.4);
  padding-bottom: 0.35em;
  transition: border-color 0.3s var(--ease);
}
.statement-links a:hover { border-color: #fff; }
.is-paper .statement-links a { border-color: var(--line); }
.is-paper .statement-links a:hover { border-color: var(--ink); }

/* the six stages, set as a quiet list on a statement panel */
.stage-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr));
  gap: 1px;
  width: min(100% - var(--pad) * 2, var(--wrap));
  background: rgba(255, 255, 255, 0.18);
  text-align: left;
}
.stage-list li { background: var(--dark); padding: clamp(0.9rem, 2.6vw, 1.4rem) 1.2rem; }
.stage-list b { display: block; font-size: var(--step--1); letter-spacing: 0.18em; text-transform: uppercase; opacity: 0.55; margin-bottom: 0.5rem; }
.stage-list span { font-weight: 600; font-size: var(--step-0); letter-spacing: 0.04em; }

/* scroll hint, bottom right, gone for good on first scroll */
.scroll-hint {
  position: fixed;
  right: var(--pad); bottom: var(--pad);
  z-index: 50;
  margin: 0;
  color: #fff;
  font-size: var(--step--1); font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase;
  transition: opacity 0.4s var(--ease);
}
.scroll-hint.is-hidden { opacity: 0; }

/* 9. Inner pages -------------------------------------------------------- */
.page-inner main { padding-top: var(--mast-h); }
.page-hero { padding-block: clamp(2.5rem, 2rem + 3vw, 4.5rem) clamp(1.5rem, 1rem + 2vw, 3rem); }
/* Projects shares the About and Services title treatment */
.page-hero h1 { font-size: var(--step-2); text-transform: lowercase; margin-bottom: 0.6em; }
/* a project page opens with the way back to the grid, sitting on the title line */
.page-hero--back { display: flex; align-items: baseline; gap: clamp(0.6rem, 2vw, 1.1rem); }
.back-link {
  display: inline-block;
  font-size: var(--step-2); line-height: 1; text-decoration: none;
  color: var(--ink-soft);
  transition: color 0.25s var(--ease), transform 0.25s var(--ease);
}
.back-link:hover { color: var(--ink); transform: translateX(-3px); }
.page-hero .lede { max-width: 54ch; }
/* About: title, then the whole statement as one column at one size. */
.page-copy { padding-block: clamp(2.5rem, 2rem + 3vw, 4.5rem) var(--section); }
.page-copy h1 { font-size: var(--step-2); text-transform: lowercase; margin-bottom: 0.6em; }
.page-copy p { font-size: clamp(1.08rem, 1.02rem + 0.24vw, 1.24rem); }

/* Services: the six stages down the page, no numerals and no rules. What
   holds them apart is air and the tracked uppercase name â the prose stops
   well short of the page edge, so the column has a wide right margin rather
   than a box around it. */
.schedule { margin-top: clamp(1.5rem, 1.2rem + 1.4vw, 2.5rem); }
.schedule-item + .schedule-item { margin-top: clamp(2.4rem, 1.8rem + 2.4vw, 4rem); }
.schedule-item h2 {
  font-size: var(--step-0); font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink); margin-bottom: 0.9em;
}
.schedule-item p { max-width: 58ch; }

/* 10. Services and stages ------------------------------------------------ */
.service-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
}
.service-grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr)); }
.service { padding: clamp(1.5rem, 1rem + 1.6vw, 2.5rem); background: var(--card); transition: background-color 0.35s var(--ease); }
.service:hover { background: var(--paper-2); }
.service .mark { width: 2rem; height: 2px; margin-bottom: 1.1rem; }
.service h3 { font-size: var(--step-1); margin-bottom: 0.5em; }
.service p { font-size: 0.97rem; }
.service-no { display: block; margin-bottom: 0.9rem; font-size: 0.78rem; font-weight: 600; letter-spacing: 0.2em; text-transform: uppercase; color: var(--ink-soft); }

.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(12.5rem, 100%), 1fr)); gap: var(--gap); }
.step { padding-top: 1.2rem; border-top: 3px solid var(--ink); }
.step-no { display: block; margin-bottom: 0.6rem; font-size: 0.78rem; font-weight: 600; letter-spacing: 0.2em; color: var(--ink-soft); }
.step h3 { font-size: var(--step-1); margin-bottom: 0.4em; }
.step p { font-size: 0.95rem; }

.cta { background: var(--paper-2); }
.cta-inner { display: grid; gap: var(--gap); align-items: center; }
.cta .section-title { max-width: 18ch; margin-bottom: 0.6rem; }
.cta-actions { display: flex; flex-wrap: wrap; gap: 0.8rem; }

/* 11. Entries, forms, detail lists ---------------------------------------- */
.filters { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 1.25rem; padding-bottom: 1.25rem; font-size: 0.95rem; }
.filters-label { color: var(--ink-soft); }
.filters button {
  padding: 0.3rem 0; background: none; border: 0;
  border-bottom: 2px solid transparent;
  font: inherit; color: var(--ink-2); cursor: pointer;
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.filters button:hover { color: var(--ink); }
.filters button[aria-pressed="true"] { color: var(--ink); font-weight: 600; border-color: var(--ink); }

/* Square tiles on a four-column field with every other cell left empty, so the
   projects step down the page in a checkerboard and no two ever touch. Each
   tile names its column and lets the row fall out of it: sparse auto-placement
   never back-fills, so 1/3 lands on one row and 2/4 drops to the next. Six
   projects make three rows. Add a seventh and the pattern simply carries on. */
.tiles { display: grid; grid-template-columns: 1fr; gap: 0; }
.tile {
  position: relative; display: block; overflow: hidden;
  aspect-ratio: 1;
  text-decoration: none; color: #fff; background: var(--dark);
}
.tile--wide { grid-column: 1 / -1; aspect-ratio: 21 / 8; }
.tile[hidden] { display: none; }
.tile .frame { position: absolute; inset: 0; aspect-ratio: auto; transition: transform 1.1s var(--ease); }
/* the scrim was there to carry the caption. With the captions gone it sits
   clear, and only comes up on hover, so a tile still answers the pointer. */
.tile::after {
  content: ""; position: absolute; inset: 0;
  background: rgba(var(--scrim), 0);
  transition: background 0.4s var(--ease);
}
.tile:hover .frame { transform: scale(1.05); }
.tile:hover::after, .tile:focus-visible::after { background: rgba(var(--scrim), 0.22); }
.tile-body { position: absolute; inset: auto 1.5rem 1.4rem; z-index: 2; }
.tile-title { display: block; font-size: var(--step-2); font-weight: 800; line-height: 1.05; letter-spacing: -0.02em; color: var(--title); }
.tile-sub { display: block; margin-top: 0.3rem; font-size: 0.95rem; color: rgba(255, 255, 255, 0.88); }
.tile-badge {
  position: absolute; top: 0; right: 0; z-index: 2;
  padding: 0.5rem 0.9rem; background: #fff; color: var(--ink);
  font-size: 0.68rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase;
}
.tile--cta { display: grid; place-content: center; gap: 0.9rem; padding: 2rem; text-align: center; background: var(--dark); }
.tile--cta::after { display: none; }
.tile--cta .tile-sub { max-width: 30ch; }
.tile--cta .link-arrow { color: #fff; justify-content: center; border-color: rgba(255,255,255,0.4); }
.tile--cta:hover { background: #21484a; }

.work-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 1rem 2rem; padding-block: clamp(2.5rem, 1.5rem + 3vw, 4.5rem) clamp(1.25rem, 1rem + 1vw, 2rem); }
.work-head h2 { margin: 0; font-size: var(--step-3); }

.entry {
  display: grid; gap: var(--gap);
  padding-block: clamp(2.25rem, 1.5rem + 3vw, 4rem);
  border-top: 1px solid var(--line-soft);
  scroll-margin-top: calc(var(--mast-h) + 1rem);
}
.entry:first-of-type { border-top: 0; }
.entry h2 { font-size: var(--step-2); margin-bottom: 0.35em; }
.entry .frame { aspect-ratio: 3 / 2; }
.entry-tag { display: inline-block; margin-bottom: 0.9rem; font-size: var(--step--1); font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-soft); }
.entry-facts { margin-top: 1.5rem; font-size: 0.92rem; }
.entry-facts div { display: flex; justify-content: space-between; gap: 1.5rem; padding: 0.6rem 0; border-bottom: 1px solid var(--line-soft); }
.entry-facts div:first-child { border-top: 1px solid var(--line-soft); }
.entry-facts dt { color: var(--ink-soft); }
.entry-facts dd { margin: 0; text-align: right; color: var(--ink); }
.entry-back { margin-top: clamp(2rem, 1.5rem + 2vw, 3.5rem); }

.form-grid { display: grid; gap: 1.3rem; max-width: 42rem; }
.field { display: grid; gap: 0.45rem; }
.field label { font-size: var(--step--1); font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-soft); }
.field input, .field select, .field textarea {
  width: 100%; padding: 0.85rem 1rem;
  font: inherit; color: var(--ink);
  background: var(--card); border: 1px solid var(--line); border-radius: 0;
  transition: border-color 0.25s var(--ease);
}
.field textarea { min-height: 9rem; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--ink); }
.form-row { display: grid; gap: 1.3rem; }
.form-note { font-size: 0.88rem; color: var(--ink-soft); max-width: 42rem; }

.detail-list { margin: 0; }
.detail-list > div { display: grid; gap: 0.2rem; padding: 1rem 0; border-bottom: 1px solid var(--line-soft); }
.detail-list > div:first-child { border-top: 1px solid var(--line-soft); }
.detail-list dt { font-size: var(--step--1); font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-soft); }
.detail-list dd { margin: 0; font-size: var(--step-1); color: var(--ink); }

/* contact card: place heading, plain address, then T / E lines with accent labels */
.contact-card h1, .contact-card h2 { font-size: var(--step-3); margin-bottom: 0.9em; }
.contact-card__address { font-size: var(--step-1); line-height: 1.65; color: var(--ink-2); margin-bottom: 2.2rem; }
.contact-card__line { margin: 0 0 0.4em; font-size: var(--step-1); color: var(--ink-2); }
.contact-card__line b { font-weight: 700; color: var(--accent); margin-right: 0.3em; }
.contact-card__line a { text-decoration: none; color: inherit; }
.contact-card__line a.contact-card__mail { color: var(--accent); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.25em; }

/* contact page: teal ground, grey enquiry box */
body.page-contact { background: var(--dark); color: rgba(255, 255, 255, 0.85); }
body.page-contact .section--tint { background: transparent; }
body.page-contact .contact-card__address,
body.page-contact .contact-card__line { color: rgba(255, 255, 255, 0.85); }
/* teal accents vanish on the teal ground, so the labels go title-grey here */
body.page-contact .contact-card__line b { color: var(--title); }
/* the address and phone sit at 85% white; the email goes to full white so the
   one link on the card is the brightest thing on it. Title-grey read at
   3.4:1 on the teal, which is under AA for text this size. */
body.page-contact .contact-card__line a.contact-card__mail { color: #fff; }
/* the form sits straight on the teal; only the response boxes go grey */
body.page-contact .enquiry .field input,
body.page-contact .enquiry .field select,
body.page-contact .enquiry .field textarea {
  background: #808080;
  border-color: rgba(255, 255, 255, 0.35);
  color: #fff;
}
body.page-contact .enquiry .field input::placeholder,
body.page-contact .enquiry .field textarea::placeholder { color: rgba(255, 255, 255, 0.65); }
body.page-contact .enquiry .field input:focus,
body.page-contact .enquiry .field select:focus,
body.page-contact .enquiry .field textarea:focus { border-color: #fff; }
body.page-contact .enquiry .field label,
body.page-contact .enquiry .intro-note { color: rgba(255, 255, 255, 0.8); }
body.page-contact .enquiry .form-note { color: rgba(255, 255, 255, 0.6); }
/* the solid teal button needs a white edge to read on the teal ground */
body.page-contact .enquiry .btn--solid { border-color: #fff; }
body.page-contact .enquiry .btn--solid:hover { color: #fff; }
@media (max-width: 48em) {
  .field input, .field select, .field textarea { width: 85%; margin-inline: auto; }
}
/* 12. Footer -------------------------------------------------------------- */
.site-foot {
  padding-block: clamp(3rem, 2rem + 3vw, 4.5rem) 1.75rem;
  background: var(--dark);
  color: rgba(255, 255, 255, 0.8);
  font-size: 0.94rem;
}
.foot-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr)); gap: 2.25rem var(--gap); }
.foot-brand .brand { position: static; font-size: var(--step-1); color: var(--title); margin-bottom: 1rem; }
.foot-title { margin-bottom: 1rem; font-size: var(--step--1); font-weight: 600; letter-spacing: 0.18em; text-transform: uppercase; color: var(--title); }
.foot-list li + li { margin-top: 0.45rem; }
.site-foot a { text-decoration: none; transition: color 0.25s var(--ease); }
.site-foot a:hover { color: #fff; }
.foot-base {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.5rem 1.5rem;
  margin-top: clamp(2.25rem, 1.5rem + 2vw, 3.5rem);
  padding-top: 1.4rem;
  border-top: 1px solid rgba(255, 255, 255, 0.16);
  font-size: 0.82rem; color: rgba(255, 255, 255, 0.6);
}
.foot-base p { margin: 0; }

/* 13. Photography ---------------------------------------------------------- */
.photo { display: block; width: 100%; height: 100%; object-fit: cover; background: var(--paper-2); }
.tile .photo { position: absolute; inset: 0; transition: transform 1.1s var(--ease); }
.tile:hover .photo { transform: scale(1.05); }
.entry-figure .photo { aspect-ratio: 3 / 2; }
.entry-more {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
  gap: 1px; margin-top: var(--gap);
  background: var(--line-soft);
}
.entry-more .photo { aspect-ratio: 4 / 3; }

/* A drawing is not a photograph. Plans and elevations are letterboxed on white
   so the whole sheet survives — cropping one to fill a 4:3 box loses the ends. */
.photo--draw { object-fit: contain; background: #fff; padding: 0.7rem; }
/* some sheets are drawn white-on-black; those want the dark ground, not paper */
.photo--draw.photo--ink { background: #101010; }

/* blur-up: an image arrives out of focus and resolves */
html.js img.blur-up { opacity: 0; filter: blur(14px); }
html.js img.blur-up.is-loaded { opacity: 1; filter: none; transition: opacity 0.6s var(--ease), filter 0.6s var(--ease); }

/* 14. Lightbox ------------------------------------------------------------- */
/* The button is invisible: it exists so a photograph can be reached by keyboard
   and announced as something you can open. */
.photo-btn {
  display: block; width: 100%; padding: 0; margin: 0;
  border: 0; background: none; cursor: zoom-in;
}
.photo-btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

body.lightbox-open { overflow: hidden; }
.lightbox {
  position: fixed; inset: 0; z-index: 400;
  display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: clamp(0.5rem, 2vw, 2rem); padding: var(--pad);
  background: rgba(var(--scrim), 0.97);
}
.lightbox[hidden] { display: none; }
.lightbox__figure { grid-column: 2; margin: 0; display: grid; gap: 1rem; justify-items: center; }
.lightbox__figure img {
  max-width: 100%; max-height: 78vh;
  width: auto; height: auto; object-fit: contain;
}
.lightbox__figure figcaption {
  max-width: 60ch; text-align: center;
  font-size: var(--step--1); line-height: 1.5; color: rgba(255, 255, 255, 0.85);
}
.lightbox__step {
  display: grid; place-content: center;
  width: clamp(2.5rem, 7vw, 3.75rem); height: clamp(2.5rem, 7vw, 3.75rem);
  padding: 0; border: 0; background: none; cursor: pointer;
  font-size: 2.4rem; line-height: 1; color: #fff;
  transition: opacity 0.25s var(--ease);
}
.lightbox__step:hover { opacity: 0.6; }
.lightbox__step--prev { grid-column: 1; }
.lightbox__step--next { grid-column: 3; }
.lightbox__close {
  position: absolute; top: var(--pad); right: var(--pad);
  padding: 0.5rem 0.9rem; border: 1px solid rgba(255, 255, 255, 0.45);
  background: none; cursor: pointer; color: #fff;
  font-size: var(--step--1); font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase;
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease);
}
.lightbox__close:hover { background: #fff; color: var(--ink); }
.lightbox__count {
  position: absolute; left: 0; right: 0; bottom: var(--pad);
  margin: 0; text-align: center; color: rgba(255, 255, 255, 0.7);
}
.lightbox :focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

/* on a phone the arrows would eat the picture, so they sit under it */
@media (max-width: 34em) {
  .lightbox { grid-template-columns: 1fr 1fr; align-content: center; }
  .lightbox__figure { grid-column: 1 / -1; }
  .lightbox__step--prev { grid-column: 1; justify-self: end; }
  .lightbox__step--next { grid-column: 2; justify-self: start; }
}

/* 15. Frames â CSS placeholders for projects with no photography yet -------- */
.frame {
  --sky-a: #aeb9bd; --sky-b: #e7e4dd; --ground: #cfc8bb;
  --mass: #363a31; --mass-2: #50554a;
  --win: 10px; --mass-x: 9%; --mass-w: 46%; --mass-h: 56%;
  --gable-x: 12%; --gable-w: 30%; --gable-h: 44%; --horizon: 62%;
  position: relative; display: block; overflow: hidden;
  aspect-ratio: 4 / 3;
  background-color: var(--sky-b);
  background-image:
    repeating-linear-gradient(0deg, rgba(20, 20, 20, 0.04) 0 1px, transparent 1px 4px),
    linear-gradient(180deg, var(--sky-a) 0%, var(--sky-b) var(--horizon), var(--ground) var(--horizon), color-mix(in srgb, var(--ground) 78%, #000) 100%);
  box-shadow: inset 0 0 7rem rgba(var(--scrim), 0.3);
  filter: grayscale(1) contrast(1.06) sepia(0.45) hue-rotate(142deg) saturate(0.9);
}
.frame::before, .frame::after { content: ""; position: absolute; bottom: 0; }
.frame::before {
  left: var(--mass-x); width: var(--mass-w); height: var(--mass-h);
  background-color: var(--mass);
  background-image:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.13) 0 calc(var(--win) * 0.9), transparent calc(var(--win) * 0.9) calc(var(--win) * 2.4)),
    repeating-linear-gradient(180deg, rgba(0, 0, 0, 0.22) 0 1px, transparent 1px calc(var(--win) * 2.1)),
    linear-gradient(180deg, color-mix(in srgb, var(--mass) 82%, #fff) 0%, var(--mass) 55%);
}
.frame::after {
  right: var(--gable-x); width: var(--gable-w); height: var(--gable-h);
  background-color: var(--mass-2);
  background-image: linear-gradient(100deg, rgba(255, 255, 255, 0.14) 0 42%, rgba(0, 0, 0, 0.16) 42% 100%);
  clip-path: polygon(0% 36%, 50% 0%, 100% 36%, 100% 100%, 0% 100%);
}
.frame--garden { --sky-a: #c4c4c4; --sky-b: #ededed; --ground: #6f6f6f; --mass: #383838; --mass-2: #565656; --win: 16px; --mass-x: 8%; --mass-w: 62%; --mass-h: 40%; --gable-x: 6%; --gable-w: 24%; --gable-h: 52%; --horizon: 66%; }
.frame--stone  { --sky-a: #a5a5a5; --sky-b: #ebebeb; --ground: #b0b0b0; --mass: #8d8d8d; --mass-2: #6f6f6f; --win: 9px;  --mass-x: 16%; --mass-w: 44%; --mass-h: 58%; --gable-x: 11%; --gable-w: 30%; --gable-h: 50%; }
.frame--timber { --sky-a: #cbcbcb; --sky-b: #f1f1f1; --ground: #838383; --mass: #4f4f4f; --mass-2: #676767; --win: 13px; --mass-x: 20%; --mass-w: 38%; --mass-h: 44%; --gable-x: 14%; --gable-w: 32%; --gable-h: 58%; --horizon: 70%; }
.frame--harbour{ --sky-a: #7c7c7c; --sky-b: #d6d6d6; --ground: #5e5e5e; --mass: #464646; --mass-2: #5a5a5a; --win: 7px;  --mass-x: 6%;  --mass-w: 66%; --mass-h: 56%; --gable-x: 4%;  --gable-w: 22%; --gable-h: 42%; }
.frame--brick  { --sky-a: #9c9c9c; --sky-b: #e2e2e2; --ground: #8a8a8a; --mass: #5d5d5d; --mass-2: #737373; --win: 8px;  --mass-x: 10%; --mass-w: 56%; --mass-h: 50%; --gable-x: 8%;  --gable-w: 28%; --gable-h: 44%; }
.frame--drawing{ --sky-a: #ededed; --sky-b: #f7f7f7; --ground: #e4e4e4; --mass: #dcdcdc; --mass-2: #d2d2d2; --win: 18px; --mass-x: 12%; --mass-w: 50%; --mass-h: 50%; }

/* 16. Motion --------------------------------------------------------------- */
.js [data-reveal] { opacity: 0; transform: translateY(1.25rem); transition: opacity 0.8s var(--ease), transform 0.8s var(--ease); }
.js [data-reveal].is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
  [data-reveal] { opacity: 1 !important; transform: none !important; }

  /* The intro still happens, but as plain fades: the lockup sits parked in the
     corner at its final size, the name fades in, the role follows, the dark
     ground dissolves. No travel, no shrink, no wipe, no zoom. */
  html.js .page-home .intro {
    animation: intro-clear 0.5s ease 1.5s forwards !important;
  }
  html.js .page-home .intro .intro__mark {
    font-size: var(--wordmark);
    transform: none;
    clip-path: none;
    animation: none !important;
  }
  html.js .page-home .intro .intro__name,
  html.js .page-home .intro .intro__role { opacity: 0; }
  html.js .page-home .intro .intro__name { animation: intro-fade 0.5s ease 0.1s forwards !important; }
  html.js .page-home .intro .intro__role { animation: intro-fade-dim 0.5s ease 0.6s forwards !important; }
  html.js .page-home .carousel { opacity: 1; animation: none !important; }
  html.js .carousel-track { transition: none !important; }
  html.js body { opacity: 1; }
  html.js img.blur-up { opacity: 1; filter: none; }
}
@keyframes intro-fade     { to { opacity: 1; } }
@keyframes intro-fade-dim { to { opacity: 0.75; } }

/* 17. Breakpoints ----------------------------------------------------------- */
@media (hover: hover) and (min-width: 900px) {
  /* captions stay out of the way until you ask for them */
  .panel__caption { opacity: 0; transform: translateY(8px); transition: opacity 0.4s var(--ease), transform 0.4s var(--ease); }
  a.panel:hover .panel__caption,
  a.panel:focus-visible .panel__caption { opacity: 1; transform: none; }
  .carousel .panel__caption { opacity: 1; transform: none; }
}

@media (min-width: 48em) {
  .grid--intro { grid-template-columns: minmax(8rem, 15%) 1fr; }
  .cta-inner { grid-template-columns: 1fr auto; }
  .form-row { grid-template-columns: 1fr 1fr; }
  .tiles { grid-template-columns: repeat(4, 1fr); }
  .tiles .tile:nth-child(4n + 1) { grid-column: 1; }
  .tiles .tile:nth-child(4n + 2) { grid-column: 3; }
  .tiles .tile:nth-child(4n + 3) { grid-column: 2; }
  .tiles .tile:nth-child(4n + 4) { grid-column: 4; }
  .entry { grid-template-columns: 1fr 1fr; align-items: center; }
  .entry:nth-of-type(even) .entry-figure { order: 2; }
  .entry-body { max-width: 46ch; }
  .tile-body { inset: auto 2rem 1.8rem; }
  /* A long elevation gets two cells, or it is unreadable at thumbnail size.
     The lightbox script wraps each photograph in a button, so the span has to
     land on the button once the script has run, and on the image before it. */
  .entry-more > .photo--wide,
  .entry-more > .photo-btn:has(.photo--wide) { grid-column: span 2; }
}

@media (min-width: 62em) {
}


@media print {
  .masthead, .menu, .menu-toggle, .intro, .scroll-hint, .btn, .frame, .filters { display: none !important; }
  body { background: #fff; color: #000; font-size: 11pt; opacity: 1 !important; }
  .panel { height: auto; }
  .panel--statement, .site-foot, .statement-band { background: #fff; color: #000; }
}
