/* ---------------------------------------------------------------------------
   Chris Boddy — one-page site.
   Type sizes are given in pt in the design, so they are written as pt here and
   interpolated with clamp(): the low end is the mobile figure, the high end the
   desktop one, so both land exactly rather than being approximated.
   --------------------------------------------------------------------------- */

@font-face{
  font-family:Poppins; font-style:normal; font-weight:400; font-display:swap;
  src:url('fonts/poppins-400.woff2') format('woff2');
}
@font-face{
  font-family:Poppins; font-style:normal; font-weight:600; font-display:swap;
  src:url('fonts/poppins-600.woff2') format('woff2');
}

:root{
  --blue:#acc6f0;               /* closed panel */
  --blue-hover:#a4c0ee;         /* rollover, ~4% darker */
  --label-open:#a9c2ef;         /* label once the panel is open, on white */
  --ink:#708391;                /* name and body copy */
  --ink-dark:#4e5a64;           /* contact / connect — deliberately darker */
  --white:#ffffff;
  --ease:cubic-bezier(0.77, 0, 0.175, 1);   /* quart in-out */
  --dur:620ms;

  /* Sized so "Copywriting, narrative" keeps its line break at every width.
     7.52vw puts a 390px phone on 22pt and tops out at the designed 50pt; the
     24px floor is for anything narrower, where the break needs the type to
     keep shrinking. Leading is the unitless 1.14 on .hero-type, so it stays
     proportional at every size. */
  --fs-hero:clamp(24px, 7.52vw, 50pt);
  /* mobile 14pt -> desktop 20pt. Same value for both now, kept as two
     variables so they can diverge again without touching the rules. */
  --fs-intro:clamp(14pt, 2.22vw, 20pt);
  --fs-client:clamp(14pt, 2.22vw, 20pt);
  /* Leading is 26.67pt desktop / 20pt mobile: desktop keeps its 1:1.333, and
     mobile sits a touch looser at 1:1.43, which small text wants. An absolute
     clamp rather than a unitless ratio, because the two ends differ. Used by
     the panel copy and the footer copy alike. */
  --lh-copy:clamp(20pt, 2.96vw, 26.67pt);
  /* The footer matches the panel copy at both ends. Kept as its own tokens
     rather than reusing the panel ones, so the two can be moved apart again
     without one dragging the other. */
  --fs-outro:clamp(14pt, 2.22vw, 20pt);
  --lh-outro:clamp(20pt, 2.96vw, 26.67pt);
  /* mobile 18pt -> desktop 18pt for the small stuff */
  --fs-meta:clamp(11pt, 1.1vw, 13pt);
  /* mobile 12pt -> desktop 16pt. 1.78vw tops out at 1200px, the same width the
     panel copy reaches its ceiling, so the two settle together. */
  --fs-label:clamp(12pt, 1.78vw, 16pt);

  --gutter:clamp(20px, 5vw, 64px);
  /* Space under a panel's copy: a shade more than the measure above it, so the
     copy is not pressed against the panel below. Derived rather than set, so
     the whole panel's spacing moves from one number. */
  --panel-pad:calc(var(--gap-open) * 2.25);
  --gap-open:clamp(14px, 1.7vw, 24px);    /* tightened space inside an open head */
  --veil:clamp(36px, 5vh, 72px);   /* softened edge while a panel moves */
  color-scheme:light;
}

*{box-sizing:border-box}
html{scroll-behavior:auto}          /* scrolling is tweened in JS, with --ease */
body{
  margin:0; background:var(--white); color:var(--ink);
  /* The scroll is tweened to a position worked out from the panel heights. Scroll
     anchoring would adjust for the closing panel as well, compensating twice and
     overshooting the target. */
  overflow-anchor:none;
  font-family:Poppins, system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing:antialiased;
}
img{max-width:100%; display:block}

/* ---------------- shared field band (header + footer) ---------------- */
.field{position:relative; overflow:hidden; background:#e3e3e3}
.field canvas{position:absolute; inset:0; width:100%; height:100%; display:block}
.field > .inner{position:relative}

/* ---------------- header ---------------- */
/* 85% of the viewport, so the introduction panel is already breaking the
   bottom edge on load. svh keeps it honest on phones, where vh counts the
   address bar that is about to disappear. */
.hero{height:85vh; height:85svh; display:flex; flex-direction:column}
.topbar{
  position:relative; display:flex; justify-content:space-between; align-items:center;
  gap:16px; padding:clamp(16px, 2.4vw, 30px) var(--gutter);
  font-size:var(--fs-meta); color:var(--ink-dark);
}
.topbar .label{opacity:.95}
.hero-type{
  position:relative; flex:1 1 auto; display:flex; flex-direction:column;
  align-items:center; justify-content:center; text-align:center;
  padding:0 var(--gutter) clamp(40px, 6vw, 80px);
  font-size:var(--fs-hero); line-height:1.14; letter-spacing:-0.01em;
  text-wrap:balance;
}
.hero-type h1, .hero-type p{margin:0; font-size:1em}
.hero-type h1{font-weight:600; color:var(--ink-dark)}
/* the two blocks sit flush, so their spacing is the 1.14 line box;
   0.228em adds 20% to it */
.hero-type p{font-weight:400; color:var(--white); margin-top:0.228em}

/* ---------------- animated underline ---------------- */
.ul{
  position:relative; color:var(--white); text-decoration:none; font-weight:600;
  padding-bottom:2px;
}
.ul::after{
  content:''; position:absolute; left:0; right:0; bottom:0; height:1.5px;
  background:currentColor; transform:scaleX(0); transform-origin:left center;
  transition:transform var(--dur) var(--ease);
}
.ul:hover::after, .ul:focus-visible::after{transform:scaleX(1)}
.ul:focus-visible{outline:2px solid currentColor; outline-offset:4px; border-radius:2px}

/* icon buttons replace the words on narrow screens */
.icon-links{display:none; gap:10px}
.icon-links a{
  width:44px; height:44px; border-radius:50%; background:var(--white);
  display:grid; place-items:center; color:var(--ink-dark);
  transition:transform var(--dur) var(--ease);
}
.icon-links a:hover{transform:translateY(-2px)}
.icon-links svg{width:20px; height:20px; fill:currentColor}

/* ---------------- panels ---------------- */
.panels{background:var(--blue); border-top:1px solid rgba(255,255,255,.6)}
.panel + .panel > .panel-head{border-top:1px solid rgba(255,255,255,.6)}

.panel-head{
  -webkit-appearance:none; appearance:none; border:0; margin:0; width:100%;
  display:flex; align-items:center; justify-content:center; text-align:center;
  padding:clamp(26px, 3.4vw, 44px) var(--gutter);
  background:var(--blue); color:var(--white); cursor:pointer;
  font-family:inherit; font-size:var(--fs-label); font-weight:600;
  letter-spacing:.10em; text-transform:uppercase; line-height:1.5;
  /* the colour rollover is linear; only the label colour carries the easing */
  transition:background-color 150ms linear, color var(--dur) var(--ease),
             padding var(--dur) var(--ease), line-height var(--dur) var(--ease);
}
.panel-head:hover{background:var(--blue-hover)}
.panel-head:focus-visible{outline:2px solid var(--ink-dark); outline-offset:-4px}
/* The logo is painted with currentColor through an alpha mask, so it simply
   follows the head's colour — white when closed, pale blue when open — instead
   of needing a second asset or a filter that only approximates the hue. */
.logo{
  /* One height for the row, nudged per mark by --scale. A solid symbol and a
     thin wordmark set to the same height do not read as the same size, so the
     scales even out the ink each one carries rather than its box. */
  height:calc(clamp(26px, 2.6vw, 38px) * var(--scale, 1));
  aspect-ratio:var(--ratio);
  background:currentColor;
  -webkit-mask:var(--src) center/contain no-repeat;
          mask:var(--src) center/contain no-repeat;
  transition:background-color var(--dur) var(--ease);
}

/* open: the head joins the white body and its label goes pale blue */
/* Once open, the head is just the logo sitting above the copy, so its full
   button padding reads as a gap. Closing it up by about half ties the two
   together. Closed heads keep their original padding, and the introduction
   has its own rule below. */
.panel.is-open > .panel-head{
  background:var(--white); color:var(--label-open);
  padding-bottom:var(--gap-open);
}
.panel.is-open > .panel-head:hover{background:var(--white)}

/* The introduction panel alone drops its title once open, leaving only the
   copy. Fading the colour rather than hiding the text keeps the head clickable
   to close it, holds the layout still, and leaves the label readable to screen
   readers. It rides the same colour transition as every other head. */
/* Unlike the others, this head changes size as well as colour when it opens and
   closes. At the shared 150ms its blue arrived while it was still two thirds
   grown, reading as a stray bar. is-moving is only present while the panel is
   in motion, so this slows the colour to the panel's own timing without
   touching the 150ms rollover. */
#panel-intro.is-moving > .panel-head{
  transition:background-color var(--dur) var(--ease), color var(--dur) var(--ease),
             padding var(--dur) var(--ease), line-height var(--dur) var(--ease);
}

#panel-intro.is-open > .panel-head{
  color:transparent; line-height:0;
  /* With the title gone this head is nothing but space. It used to match the
     padding under the copy, which read as a hole now the logo panels have
     tightened, so it takes the same measure they do. */
  padding-top:var(--gap-open);
  padding-bottom:var(--gap-open);
}

/* the 0fr -> 1fr grid transition animates height without measuring it in JS */
.panel-body{
  display:grid; grid-template-rows:0fr; background:var(--white);
  transition:grid-template-rows var(--dur) var(--ease);
}
.panel.is-open > .panel-body{grid-template-rows:1fr}
.panel-body > .clip{overflow:hidden}
/* While the panel is moving, the copy is faded out into the edge rather than
   ending on a hard slice, so it reads as passing behind the panel below. The
   mask is only present during the movement — once open, the text is crisp. */
.panel.is-moving > .panel-body > .clip{
  -webkit-mask-image:linear-gradient(to bottom, #000 calc(100% - var(--veil)), transparent 100%);
          mask-image:linear-gradient(to bottom, #000 calc(100% - var(--veil)), transparent 100%);
}
.panel-inner{
  max-width:1040px; margin:0 auto; text-align:center;
  padding:0 var(--gutter) var(--panel-pad);
  font-size:var(--fs-client); line-height:var(--lh-copy); letter-spacing:-0.005em;
  opacity:0; transition:opacity var(--dur) var(--ease);
}
.panel.is-open > .panel-body .panel-inner{opacity:1}
.panel-inner p{margin:0}
.panel-inner p + p{margin-top:1.1em}
#panel-intro .panel-inner{font-size:var(--fs-intro)}

/* Links sitting inside the copy. A plain underline rather than the animated
   one the header and footer use: those are standalone calls to action, these
   are mid-sentence and need to look like links at rest. */
.panel-inner a{
  color:inherit; text-decoration:underline;
  text-underline-offset:0.14em; text-decoration-thickness:1px;
  transition:text-decoration-thickness 150ms linear;
}
.panel-inner a:hover{text-decoration-thickness:2px}
.panel-inner a:focus-visible{outline:2px solid currentColor; outline-offset:3px; border-radius:2px}

/* Hand-placed breaks in the copy. They are tuned to the desktop measure, where
   both the column and the type are at their full size, so below that the copy
   wraps naturally instead. The space that follows each tag in the markup is
   what keeps the words apart once the break is hidden. */
@media (max-width:1199px){
  br.brk{display:none}
}

/* The disciplines open each client panel, so they carry more weight than the
   copy below them. The introduction and Elsewhere open straight into prose,
   so they are left alone. */
#panel-google .panel-inner p:first-child,
#panel-pentagram .panel-inner p:first-child,
#panel-dyson .panel-inner p:first-child,
#panel-apple .panel-inner p:first-child{font-weight:600}

/* ---------------- footer ---------------- */
.outro{border-top:1px solid rgba(255,255,255,.6)}
.outro .inner{
  color:var(--ink-dark);          /* same darker grey as Contact / Connect */
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  text-align:center; gap:clamp(26px, 3.4vw, 48px);
  padding:clamp(64px, 9vw, 140px) var(--gutter);
  font-size:var(--fs-outro); line-height:var(--lh-outro); letter-spacing:-0.005em;
}
/* 42ch = 844px at 24pt, chosen to break the line after "organisations": that
   much of the sentence measures 804px and adding " and" takes it to 876px, so
   the break lands there with about 40px of slack either side. */
.outro p{margin:0; max-width:42ch}
.outro .cta{font-size:1em}

/* On a narrow, tall screen the last panels run out of page to scroll against,
   so they stop short of the top. Giving the footer a floor in viewport units
   covers it: the shortfall grows with screen height, so the remedy has to as
   well, and a fixed padding that worked on one phone fell short on a taller
   one. The field fills the extra, and desktop reaches the top unaided. */
@media (max-width:900px){
  .outro{min-height:70vh; min-height:70svh}
}

@media (max-width:760px){
  .topbar .worded{display:none}
  .icon-links{display:flex}
  .topbar{justify-content:flex-end}
  /* 24ch left "world." stranded on a fourth line. 27ch sets it in three with
     four words on the last, and sits mid-way through the 26-28ch band that
     gives that break, so it holds rather than flipping. */
  .outro p{max-width:27ch}
}

/* Used for a beat while JS measures a settled layout; see closedHeadHeight(). */
.measuring, .measuring *{transition:none !important}

@media (prefers-reduced-motion:reduce){
  *{transition-duration:1ms !important}
}
