/* ==========================================================================
   Thorianne. Brand Development, Marketing & Launch.
   Palette, type and rules from the Visual Brand Identity Guidelines V1.0.
   Square corners, hairlines, no drop shadows. 60/30/10.
   ========================================================================== */

:root{
  --canvas:#F4F1EA;
  --canvas-2:#FBFAF8;
  --deep:#16303E;
  --deep-2:#1C3D4D;
  --panel:#E5DFD2;
  --accent:#8A6A3C;         /* brand bronze. Rules, keylines, marks. Decorative only. */
  --accent-text:#7C5E33;    /* the same bronze darkened for small uppercase labels,
                               because 11px type has to clear 4.5:1 and #8A6A3C does not */
  --accent-hi:#6F5430;
  --accent-dk:#C79A55;
  --mist:#9FB4BE;
  --teal:#3E7180;        /* mid-tone band. cream text 4.80:1. never pair with bronze */
  --teal-2:#35626F;
  --ink:#1C3D4D;
  --ink-2:#4B6774;         /* darkened: 4.27 -> 4.53 on sand */
  --ink-3:#54656E;         /* darkened: 4.12 -> 4.57 on sand */          /* darkened from #7B909B: small text needs 4.5:1 */
  --rule:#DCD4C5;
  --rule-2:#C3B9A6;
  --rule-dk:rgba(159,180,190,.24);
  --rule-dk-2:rgba(159,180,190,.42);

  --display:"Fraunces",Georgia,"Times New Roman",serif;
  --sans:"Instrument Sans",-apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,"SFMono-Regular",Menlo,monospace;

  --wrap:1180px;
  --gutter:clamp(20px,5vw,60px);
  --band:clamp(72px,9vw,136px);

  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-soft:cubic-bezier(.4,0,.2,1);

  color-scheme:light;
}

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

html,body{overflow-x:hidden;overflow-x:clip}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scroll-padding-top:92px}

body{
  margin:0;
  background:var(--canvas);
  color:var(--ink);
  font-family:var(--sans);
  font-size:16px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  font-synthesis-weight:none;
  position:relative;
}

/* One fixed environment layer behind everything, so scrolling feels like one place */
.environment{
  position:fixed;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(60% 45% at 18% 12%, rgba(138,106,60,.055), transparent 70%),
    radial-gradient(55% 40% at 88% 78%, rgba(159,180,190,.10), transparent 72%);
  animation:envdrift 96s var(--ease-soft) -24s infinite alternate;
}
@keyframes envdrift{from{transform:translate3d(0,0,0) scale(1)}to{transform:translate3d(0,-2.2%,0) scale(1.05)}}

main,.site-header,.site-footer{position:relative;z-index:1}

img,svg,video{max-width:100%}
img{height:auto;display:block}
a{color:inherit}

:where(a,button,input,select,textarea,summary):focus-visible{
  outline:2px solid var(--accent);outline-offset:3px;border-radius:0;
}

.skip{
  position:absolute;left:-9999px;top:0;z-index:100;
  background:var(--deep);color:var(--canvas);padding:12px 18px;
  font-size:.813rem;font-weight:600;letter-spacing:.05em;text-transform:uppercase;text-decoration:none;
}
.skip:focus{left:0}

.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}

/* ---------- Type ---------------------------------------------------------- */
h1,h2,h3,h4{
  font-family:var(--display);
  font-variation-settings:"SOFT" 0,"WONK" 0;
  font-weight:600;line-height:1.1;letter-spacing:-.014em;
  text-wrap:balance;margin:0;
}
h1{font-size:clamp(2.35rem,1.2rem + 4.4vw,4.4rem);font-weight:700;line-height:1.02}
h2{font-size:clamp(1.8rem,1.25rem + 2.1vw,2.85rem)}
h3{font-size:clamp(1.18rem,1.06rem + .46vw,1.42rem);letter-spacing:-.006em}
p{margin:0}

.lede{font-size:clamp(1.06rem,.98rem + .4vw,1.26rem);line-height:1.56;color:var(--ink-2);max-width:60ch}
.prose{color:var(--ink-2);max-width:62ch}
.prose p + p{margin-top:1em}
strong,b{font-weight:600;color:var(--ink)}

.eyebrow{
  font-family:var(--mono);
  font-size:.75rem;font-weight:500;letter-spacing:.17em;text-transform:uppercase;
  color:var(--accent-text);margin:0;
}

/* The rule. Solid speaks for the marketing half, dashed for the technology half,
   after the dashed crossbar in the monogram. */
.rule{display:block;width:58px;height:0;border:0;border-top:1px solid var(--accent);margin:0}
.rule-dash{border-top-style:dashed}

/* ---------- Layout -------------------------------------------------------- */
.wrap{width:100%;max-width:var(--wrap);margin-inline:auto;padding-inline:var(--gutter)}
.sec{padding-block:var(--band)}

.sec-cream{background:var(--canvas)}
.sec-paper{background:var(--canvas-2);border-block:1px solid var(--rule)}
.sec-deep{background:var(--deep);color:var(--canvas)}
.sec-deep .eyebrow{color:var(--accent-dk)}
.sec-deep .lede,.sec-deep .prose{color:var(--mist)}
.sec-deep strong,.sec-deep b{color:var(--canvas)}
.sec-deep .rule{border-top-color:var(--accent-dk)}


.head{display:grid;gap:15px;margin-bottom:clamp(38px,5vw,60px)}
.head .lede{margin-top:4px}
@media(min-width:900px){
  .head{grid-template-columns:168px minmax(0,1fr);column-gap:44px;align-items:start}
  .head > .head-label{grid-row:span 3;padding-top:11px}
}
.head-label{display:flex;flex-direction:column;gap:13px}

/* ---------- Header -------------------------------------------------------- */
.site-header{
  position:sticky;top:0;z-index:50;
  background:color-mix(in srgb,var(--canvas) 90%,transparent);
  -webkit-backdrop-filter:saturate(150%) blur(9px);  /* Safari needed the prefix until 18 */
  backdrop-filter:saturate(150%) blur(9px);
  border-bottom:1px solid var(--rule);
}
.header-in{display:flex;align-items:center;justify-content:space-between;gap:22px;min-height:72px;padding-block:13px}
.brand{display:inline-flex;align-items:center;gap:13px;text-decoration:none;color:var(--ink);flex:0 0 auto}
.brand .mark{width:19px;height:auto;flex:0 0 auto}
.brand .word{width:clamp(116px,26vw,158px);height:auto;color:var(--ink)}

.nav{display:flex;align-items:center;gap:clamp(14px,2.2vw,32px)}
.nav a{font-size:.875rem;font-weight:500;text-decoration:none;color:var(--ink-2);padding-block:5px;border-bottom:1px solid transparent;transition:color .15s var(--ease),border-color .15s var(--ease)}
.nav a:hover,.nav a[aria-current="page"]{color:var(--ink);border-bottom-color:var(--accent)}
/* .nav a sets colour at 0,1,1 and .btn only at 0,1,0, so the button needs the
   compound selector or its label inherits the nav's muted grey on navy. */
.nav a.btn{border-bottom:0;color:var(--canvas)}
.nav a.btn:hover{color:var(--ink);border-bottom-color:transparent}
.nav-links{display:flex;align-items:center;gap:clamp(14px,2.2vw,32px)}

/* ---- mobile menu -------------------------------------------------------
   Below 860px the three links were display:none with nothing to reveal
   them, on a page around 19,000px tall at phone width. The panel hangs off
   .site-header, which is position:sticky and therefore the nearest
   positioned ancestor. visibility rather than display so it can animate;
   the accent underline for aria-current still wins over the row divider
   because :hover and [aria-current] carry the extra specificity.        */
.nav-toggle{display:none;width:38px;height:38px;padding:0;place-items:center;
  border:1px solid var(--rule-2);border-radius:3px;background:transparent;cursor:pointer;
  flex:0 0 auto}
.nav-toggle span{display:block;width:16px;height:1px;background:var(--ink);position:relative;
  transition:background .2s var(--ease)}
.nav-toggle span::before,.nav-toggle span::after{content:"";position:absolute;left:0;
  width:16px;height:1px;background:var(--ink);
  transition:transform .2s var(--ease),top .2s var(--ease)}
.nav-toggle span::before{top:-5px}
.nav-toggle span::after{top:5px}
.nav-toggle[aria-expanded="true"] span{background:transparent}
.nav-toggle[aria-expanded="true"] span::before{top:0;transform:rotate(45deg)}
.nav-toggle[aria-expanded="true"] span::after{top:0;transform:rotate(-45deg)}

@media(max-width:860px){
  .nav-toggle{display:grid}
  .nav-links{
    position:absolute;top:100%;left:0;right:0;
    flex-direction:column;align-items:stretch;gap:0;
    padding:2px var(--gutter) 10px;
    background:color-mix(in srgb,var(--canvas) 96%,transparent);
    -webkit-backdrop-filter:saturate(150%) blur(9px);
    backdrop-filter:saturate(150%) blur(9px);
    border-bottom:1px solid var(--rule);
    opacity:0;visibility:hidden;transform:translateY(-6px);
    transition:opacity .22s var(--ease),transform .22s var(--ease),visibility 0s .22s;
  }
  .nav-links.open{opacity:1;visibility:visible;transform:none;
    transition:opacity .22s var(--ease),transform .22s var(--ease),visibility 0s}
  .nav-links a{padding-block:14px;border-bottom:1px solid var(--rule)}
  .nav-links a:last-child{border-bottom:0}
}
@media(prefers-reduced-motion:reduce){
  .nav-links,.nav-links.open,.nav-toggle span,
  .nav-toggle span::before,.nav-toggle span::after{transition:none}
}
/* "Start a conversation" is 224px of a 335px header at 375px wide. Beside
   the menu button it overflows by 46px and pushes that button off-screen,
   so the label shortens rather than the button being dropped. */
.btn-short{display:none}
@media(max-width:560px){
  .brand .word{width:106px}.nav{gap:13px}.nav a{font-size:.813rem}
  .btn-long{display:none}.btn-short{display:inline}
}

/* ---------- Buttons ------------------------------------------------------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  font-family:var(--sans);font-size:.8rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  text-decoration:none;white-space:nowrap;cursor:pointer;
  padding:13px 24px;border:1px solid var(--ink);background:var(--ink);color:var(--canvas);
  transition:background .17s var(--ease),color .17s var(--ease),border-color .17s var(--ease);
}
.btn:hover{background:transparent;color:var(--ink)}
.btn-ghost{background:transparent;color:var(--ink);border-color:var(--rule-2)}
.btn-ghost:hover{background:transparent;color:var(--ink);border-color:var(--ink)}
.sec-deep .btn,.site-footer .btn{background:var(--canvas);color:var(--deep);border-color:var(--canvas)}
.sec-deep .btn:hover,.site-footer .btn:hover{background:transparent;color:var(--canvas)}
.sec-deep .btn-ghost{background:transparent;color:var(--canvas);border-color:rgba(244,241,234,.34)}
.sec-deep .btn-ghost:hover{border-color:var(--canvas)}
.btn-row{display:flex;flex-wrap:wrap;gap:13px}
@media(pointer:coarse){.btn{min-height:44px;display:inline-flex;align-items:center;justify-content:center}}

.tlink{display:inline-flex;align-items:center;gap:8px;font-size:.875rem;font-weight:500;text-decoration:none;color:var(--ink);border-bottom:1px solid var(--accent);padding-bottom:2px;transition:gap .17s var(--ease)}
.tlink:hover{gap:13px}
.tlink .arr{color:var(--accent)}
.sec-deep .tlink{color:var(--canvas);border-bottom-color:var(--accent-dk)}
.sec-deep .tlink .arr{color:var(--accent-dk)}

/* ---------- Hero ---------------------------------------------------------- */
.hero{padding-block:clamp(36px,4vw,60px) 0}
.hero-grid{display:grid;gap:clamp(40px,5vw,56px)}
.hero h1{max-width:20ch}
.hero h1{margin-top:22px}
.hero .lede{margin-top:20px;max-width:52ch}
.hero .btn-row{margin-top:28px}
.hero-note{margin-top:20px;font-family:var(--mono);font-size:.719rem;letter-spacing:.04em;color:var(--ink-3)}

/* Slot the hero film drops into once it exists. */
.film-slot{position:relative;aspect-ratio:16/9;background:var(--deep);border:1px solid var(--rule-2);overflow:hidden}

/* ---------- Grids and cells ---------------------------------------------- */
.g2,.g3{display:grid}
.g2{gap:34px}
.g3{gap:30px}
@media(min-width:760px){.g2{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:clamp(34px,4vw,60px)}}
@media(min-width:960px){.g3{grid-template-columns:repeat(3,minmax(0,1fr));column-gap:clamp(30px,3.2vw,44px)}}

.cell{display:flex;flex-direction:column;gap:12px;border-top:1px solid var(--rule);padding-top:26px}
.cell p{color:var(--ink-2);font-size:.938rem}
.sec-deep .cell{border-top-color:var(--rule-dk)}
.sec-deep .cell p{color:var(--mist)}
.cell-tag{font-family:var(--mono);font-size:.688rem;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--accent-text)}
.sec-deep .cell-tag{color:var(--accent-dk)}

.panel{background:var(--panel);border:1px solid var(--rule-2);padding:clamp(26px,3.6vw,44px)}
.sec-deep .panel{background:rgba(244,241,234,.05);border-color:var(--rule-dk)}

.pull{font-family:var(--display);font-variation-settings:"SOFT" 0,"WONK" 0;font-weight:600;
  font-size:clamp(1.5rem,1.05rem + 1.9vw,2.35rem);line-height:1.18;letter-spacing:-.016em;text-wrap:balance;margin:0;max-width:22ch}

/* ---------- The two fears --------------------------------------------------*/
.fear{border-top:1px solid var(--rule-dk);padding-top:28px;display:flex;flex-direction:column;gap:14px}
.fear-a{border-top-color:var(--accent-dk)}
.fear-b{border-top-color:var(--accent-dk);border-top-style:dashed}
.fear h3{font-size:clamp(1.3rem,1.1rem + .8vw,1.7rem)}
.fear p{color:var(--mist);font-size:.969rem;max-width:44ch}

/* ---------- Table ---------------------------------------------------------*/
.tscroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.owns{width:100%;min-width:600px;border-collapse:collapse;text-align:left;font-size:.906rem}
.owns th,.owns td{padding:15px 11px;border-bottom:1px solid var(--rule);vertical-align:baseline}
.owns thead th{font-family:var(--mono);font-size:.6875rem;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);border-bottom:1px solid var(--rule-2);padding-bottom:11px}
.owns tbody th{font-weight:500;color:var(--ink);padding-left:0;padding-right:16px;width:36%}
.owns td{text-align:center;font-variant-numeric:tabular-nums}
.owns .m{font-size:1.02rem;line-height:1;color:var(--accent)}
.owns .m-no{color:var(--rule-2)}
.owns .us{background:var(--panel);padding-inline:14px}
.owns thead .us{color:var(--accent)}
.owns tbody tr:last-child th,.owns tbody tr:last-child td{border-bottom:0}
.tnote{margin-top:17px;font-size:.813rem;color:var(--ink-3);max-width:60ch}
.thint{display:none;margin-bottom:11px;font-family:var(--mono);font-size:.688rem;letter-spacing:.12em;text-transform:uppercase;color:var(--accent-text)}
@media(max-width:640px){.thint{display:block}}

/* ---------- Practice lists ------------------------------------------------ */
.practice{display:flex;flex-direction:column;gap:17px;border-top:1px solid var(--accent);padding-top:28px}
.practice-tech{border-top-style:dashed}
.kicker{font-family:var(--mono);font-size:.688rem;font-weight:500;letter-spacing:.15em;text-transform:uppercase;color:var(--accent-text)}
.list{list-style:none;margin:0;padding:0}
.list li{display:grid;grid-template-columns:17px minmax(0,1fr);gap:11px;align-items:baseline;padding-block:13px;border-top:1px solid var(--rule);font-size:.938rem;color:var(--ink-2)}
.list li:first-child{border-top:0}
.list li::before{content:"";display:block;width:11px;height:0;border-top:1px solid var(--accent);transform:translateY(-3px)}
.list-dash li::before{border-top-style:dashed}
.sec-deep .list li{border-top-color:var(--rule-dk);color:var(--mist)}

/* ---------- Ledger -------------------------------------------------------- */
.ledger{display:grid}
.lrow{display:grid;gap:9px;padding-block:clamp(26px,3vw,36px);border-top:1px solid var(--rule)}
.lrow:first-child{border-top:0;padding-top:0}
.lnum{font-family:var(--display);font-variation-settings:"SOFT" 0,"WONK" 0;font-weight:400;font-size:clamp(2rem,1.5rem + 1.9vw,3rem);line-height:.9;color:var(--accent);font-variant-numeric:tabular-nums;opacity:.85}
.lrow h3{font-size:clamp(1.3rem,1.1rem + .78vw,1.68rem)}
.lrow p{color:var(--ink-2);max-width:58ch}
@media(min-width:880px){.lrow{grid-template-columns:88px 250px minmax(0,1fr);column-gap:clamp(26px,3vw,46px);align-items:start}}

/* ---------- Work: one project at a time, not a wall of thumbnails ---------
   Each project is one self-contained .project block. To add a brand, copy the
   block in the HTML. Nothing here needs changing.
   -------------------------------------------------------------------------- */
.projects{display:grid;gap:clamp(72px,9vw,140px)}

.project{display:grid;gap:clamp(24px,3vw,38px)}
@media(min-width:960px){
  .project{grid-template-columns:minmax(0,7.4fr) minmax(0,3.6fr);column-gap:clamp(36px,4vw,64px);align-items:start}
  /* Flipping also has to swap the track widths, or the text takes the wide column. */
  .project.flip{grid-template-columns:minmax(0,3.6fr) minmax(0,7.4fr)}
  .project.flip > .p-media{order:2}
  .project.flip > .p-meta{order:1}
}

.p-media{display:grid;gap:clamp(12px,1.4vw,18px)}
.p-sub{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(12px,1.4vw,18px)}
/* Figures in a row must not stretch to the tallest one: a short image would
   then show the panel colour beneath it, which reads as a botched crop. */
.p-sub .shot{align-self:start}
@media(max-width:560px){.p-sub{grid-template-columns:repeat(2,minmax(0,1fr))}.p-sub .shot:last-child{grid-column:span 2}}
/* Milk and Coffee Kids carries four below its lead, so it runs two up. */
.p-sub.quad{grid-template-columns:repeat(2,minmax(0,1fr))}
@media(max-width:560px){.p-sub.quad{grid-template-columns:minmax(0,1fr)}.p-sub.quad .shot:last-child{grid-column:auto}}

.shot{margin:0;position:relative;overflow:hidden;background:var(--panel);border:1px solid var(--rule-2)}
.shot img{width:100%;height:auto;display:block;transition:transform 1.4s var(--ease)}
.shot:hover img{transform:scale(1.03)}

/* Micro motion: each frame wipes up into view once, then stops.
   Transform and opacity only, and it rests at a visible final state. */
.shot{clip-path:inset(0 0 100% 0);transition:clip-path 1s var(--ease)}
.in .shot{clip-path:inset(0 0 0 0)}
.in .p-sub .shot:nth-child(1){transition-delay:120ms}
.in .p-sub .shot:nth-child(2){transition-delay:220ms}
.in .p-sub .shot:nth-child(3){transition-delay:320ms}
.in.done .p-sub .shot:nth-child(1),
.in.done .p-sub .shot:nth-child(2),
.in.done .p-sub .shot:nth-child(3){transition-delay:0ms}

.p-meta{display:flex;flex-direction:column;gap:15px;padding-top:6px;border-top:1px solid var(--accent)}
.p-meta.tech{border-top-style:dashed}
.p-index{font-family:var(--mono);font-size:.688rem;font-weight:500;letter-spacing:.16em;text-transform:uppercase;color:var(--accent-text);padding-top:18px;font-variant-numeric:tabular-nums}
.p-meta h3{font-size:clamp(1.3rem,1.1rem + .8vw,1.62rem)}
.p-meta .blurb{color:var(--ink-2);font-size:.938rem;max-width:42ch}

.p-scope{list-style:none;margin:4px 0 0;padding:0;display:grid}
.p-scope li{padding-block:10px;border-top:1px solid var(--rule);font-family:var(--mono);font-size:.719rem;letter-spacing:.06em;color:var(--ink-3)}

/* Optional per project. Omit the block entirely on projects with no quote. */
.p-quote{margin-top:4px;padding-top:18px;border-top:1px solid var(--rule)}
.p-quote blockquote{margin:0;font-family:var(--display);font-variation-settings:"SOFT" 0,"WONK" 0;font-weight:600;font-size:1.06rem;line-height:1.38;letter-spacing:-.008em;color:var(--ink)}
.p-quote cite{display:block;margin-top:11px;font-family:var(--mono);font-size:.688rem;font-style:normal;letter-spacing:.11em;text-transform:uppercase;color:var(--ink-3)}

/* A story that belongs to one project, set to be read rather than skimmed. */
.p-story{margin-top:4px;padding-top:18px;border-top:1px solid var(--rule);color:var(--ink-2);font-size:.938rem;max-width:42ch}
.p-story p + p{margin-top:.9em}

.work-more{margin-top:clamp(48px,5.5vw,72px);padding-top:24px;border-top:1px solid var(--rule-2);display:flex;flex-wrap:wrap;gap:16px 28px;align-items:baseline;justify-content:space-between}
.work-more p{color:var(--ink-3);font-size:.875rem;max-width:46ch}

/* ---------- Process strip: how a piece of work got made ------------------- */
.p-process{grid-column:1 / -1;order:3;min-width:0;margin-top:clamp(28px,3.4vw,44px);padding-top:26px;border-top:1px solid var(--rule-2)}
.p-process-head{display:flex;flex-wrap:wrap;gap:10px 26px;align-items:baseline;margin-bottom:22px}
.p-process-head h4{font-family:var(--mono);font-size:.688rem;font-weight:500;letter-spacing:.16em;text-transform:uppercase;color:var(--accent-text);margin:0}
.p-process-head p{font-size:.813rem;color:var(--ink-3);max-width:58ch}

/* Three frames of the same size, so nothing is cropped and nothing is ragged. */

/* The colour reference, and the values it sits next to. */
.colour-ref{margin:0}
/* The board is painted on the page’s own canvas, so a frame round it would
   turn content that sits on the page into a rectangle pasted onto it. */
.colour-ref img{width:100%;height:auto;display:block}
/* The five values stay as text so they survive a phone and a copy paste. */
.p-values{margin-top:clamp(12px,1.5vw,18px);font-family:var(--mono);font-size:.688rem;line-height:1.8;letter-spacing:.02em;color:var(--ink-3)}
.p-values b{font-weight:400;color:var(--ink)}

.p-credit{margin-top:18px;padding-top:14px;border-top:1px solid var(--rule);font-family:var(--mono);font-size:.688rem;letter-spacing:.06em;color:var(--ink-3)}
.p-credit a{color:var(--accent-text);text-decoration:none;border-bottom:1px solid var(--rule-2)}
.p-credit a:hover{border-bottom-color:var(--accent)}

/* The two practice lines that have a portfolio point down to it. */
.list .seen{
  display:inline-block;margin-left:5px;white-space:nowrap;vertical-align:baseline;
  font-family:var(--mono);font-size:.6875rem;letter-spacing:.11em;text-transform:uppercase;
  color:var(--accent-text);text-decoration:none;
  border-bottom:1px solid var(--rule);padding-bottom:1px;
}
.list .seen::after{content:"\00a0\2193"}
.list .seen:hover{border-bottom-color:var(--accent)}
.list .seen:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

.p-note{margin-top:clamp(14px,1.6vw,20px);font-family:var(--mono);font-size:.719rem;line-height:1.7;letter-spacing:.02em;color:var(--ink-3);max-width:62ch}

.work-note{margin-top:clamp(52px,6vw,76px);padding-top:20px;border-top:1px solid var(--rule);font-size:.813rem;color:var(--ink-3);max-width:62ch}

/* ---------- Portrait ------------------------------------------------------ */
.who-grid{display:grid;gap:clamp(34px,4vw,56px)}
@media(min-width:880px){
  .who-grid{grid-template-columns:minmax(0,5fr) minmax(0,7fr);column-gap:clamp(40px,4.5vw,72px);align-items:start}
}
.portrait{margin:0;position:relative}
.portrait img{width:100%;height:auto;display:block;border:1px solid var(--rule-2);background:var(--panel)}
.portrait figcaption{
  margin-top:14px;padding-top:12px;border-top:1px solid var(--accent);
  font-family:var(--mono);font-size:.688rem;letter-spacing:.13em;text-transform:uppercase;color:var(--accent-text);
}

/* The profile sits with the portrait, not in a row of social icons. */
.portrait .plink{
  display:inline-block;margin-top:11px;
  font-family:var(--mono);font-size:.656rem;letter-spacing:.12em;text-transform:uppercase;
  color:var(--accent-text);text-decoration:none;
  border-bottom:1px solid var(--rule);padding-bottom:2px;
  transition:border-color .2s var(--ease);
}
.portrait .plink::after{content:"\00a0\2197"}
.portrait .plink:hover{border-bottom-color:var(--accent)}
.portrait .plink:focus-visible{outline:2px solid var(--accent);outline-offset:3px}

/* ---------- Qualifications ------------------------------------------------
   Two lines, both verifiable. The note after them is the part that argues. */
.creds{margin-top:clamp(26px,3vw,36px);padding-top:22px;border-top:1px solid var(--rule)}
.cred-list{margin:15px 0 0;padding:0;display:grid;gap:0}
.cred-list > div{padding-block:12px;border-top:1px solid var(--rule-2)}
.cred-list > div:first-child{border-top:0}
.cred-list dt{font-size:.969rem;color:var(--ink);font-weight:500}
.cred-list dd{
  margin:4px 0 0;display:flex;flex-wrap:wrap;gap:6px 14px;align-items:baseline;justify-content:space-between;
  font-family:var(--mono);font-size:.688rem;letter-spacing:.06em;color:var(--ink-3);
}
.cred-list .yr{color:var(--accent-text);font-variant-numeric:tabular-nums}
.cred-note{margin-top:16px;font-size:.906rem;line-height:1.66;color:var(--ink-2);max-width:56ch}

/* ---------- FAQ ----------------------------------------------------------- */
.faq{display:grid}
.faq details{border-top:1px solid var(--rule)}
.faq details:last-child{border-bottom:1px solid var(--rule)}
.faq summary{
  list-style:none;cursor:pointer;padding-block:20px;
  display:grid;grid-template-columns:minmax(0,1fr) 24px;gap:16px;align-items:center;
  font-family:var(--display);font-variation-settings:"SOFT" 0,"WONK" 0;font-weight:600;font-size:1.06rem;color:var(--ink);
}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"";width:11px;height:11px;border-right:1px solid var(--accent);border-bottom:1px solid var(--accent);transform:rotate(45deg) translate(-2px,-2px);transition:transform .3s var(--ease);justify-self:end}
.faq details[open] summary::after{transform:rotate(-135deg) translate(-3px,-3px)}
.faq .ans{padding-bottom:22px;color:var(--ink-2);font-size:.969rem;max-width:64ch}

/* ---------- Form ---------------------------------------------------------- */
.form{display:grid;gap:19px}
.field{display:grid;gap:7px}
.field label{font-family:var(--mono);font-size:.688rem;letter-spacing:.12em;text-transform:uppercase;color:var(--mist)}
.field input,.field select,.field textarea{
  font-family:var(--sans);font-size:.938rem;color:var(--canvas);background:rgba(244,241,234,.06);
  border:1px solid rgba(159,180,190,.34);border-radius:0;padding:13px 14px;width:100%;
  transition:border-color .17s var(--ease),background .17s var(--ease);
}
.field textarea{min-height:130px;resize:vertical;line-height:1.55}
.field input::placeholder,.field textarea::placeholder{color:rgba(159,180,190,.62)}
.field input:hover,.field select:hover,.field textarea:hover{border-color:var(--mist)}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--accent-dk);background:rgba(244,241,234,.09)}
.field select option{color:#1C3D4D;background:#F4F1EA}
.frow{display:grid;gap:19px}
@media(min-width:620px){.frow{grid-template-columns:repeat(2,minmax(0,1fr))}}
.fnote{font-family:var(--mono);font-size:.719rem;line-height:1.6;color:var(--mist);max-width:52ch}
.fnote a{color:var(--canvas)}
.sent{display:none;border:1px solid var(--accent-dk);padding:24px;background:rgba(199,154,85,.09)}
.sent.on{display:block}
.sent p{color:var(--canvas);font-family:var(--display);font-variation-settings:"SOFT" 0,"WONK" 0;font-weight:600;font-size:1.06rem}

/* ---------- Footer -------------------------------------------------------- */
.site-footer{background:var(--deep);color:var(--canvas);padding-block:clamp(54px,6vw,80px) 32px}
/* cream, not bronze. The guide's own misuse rule: navy on light grounds,
   cream on deep and teal, never bronze, because bronze is decorative in
   this system and the mark is not decoration. */
.fmark{display:block;height:46px;width:auto;color:var(--canvas);margin:0 0 20px}
.site-footer .word{width:152px;color:var(--canvas)}
.site-footer a{color:var(--mist);text-decoration:none}
.site-footer a:hover{color:var(--canvas)}
.fgrid{display:grid;gap:40px}
@media(min-width:840px){.fgrid{grid-template-columns:minmax(0,1.5fr) repeat(2,minmax(0,1fr));column-gap:48px}}
.fcol h4{font-family:var(--mono);font-size:.688rem;font-weight:500;letter-spacing:.15em;text-transform:uppercase;color:var(--accent-dk);margin:0 0 16px}
.fcol ul{list-style:none;margin:0;padding:0;display:grid;gap:11px;font-size:.906rem}
/* The contact column carries a second heading now that the pages exist. */
.fcol h4.f-more{margin-top:30px}
.forigin{margin-top:22px;font-size:.906rem;line-height:1.62;color:var(--mist);max-width:46ch}
.ftag{margin-top:20px;padding-top:14px;border-top:1px solid var(--accent-dk);display:inline-block;font-family:var(--mono);font-size:.6875rem;letter-spacing:.18em;text-transform:uppercase;color:var(--accent-dk)}
.fbase{margin-top:clamp(44px,5vw,64px);padding-top:20px;border-top:1px solid var(--rule-dk);display:flex;flex-wrap:wrap;gap:8px 26px;justify-content:space-between;font-family:var(--mono);font-size:.719rem;color:var(--mist)}

/* ---------- Entrances ----------------------------------------------------- */
.rise{opacity:0;transform:translateY(14px);transition:opacity .82s var(--ease),transform .82s var(--ease)}
.in.rise,.in .rise{opacity:1;transform:none}
.in .rise:nth-child(1){transition-delay:0ms}
.in .rise:nth-child(2){transition-delay:105ms}
.in .rise:nth-child(3){transition-delay:210ms}
.in .rise:nth-child(4){transition-delay:315ms}
.in .rise:nth-child(5){transition-delay:420ms}
.in .rise:nth-child(6){transition-delay:525ms}
.in .rise:nth-child(7){transition-delay:630ms}
.in .rise:nth-child(8){transition-delay:735ms}
.in .rise:nth-child(9){transition-delay:840ms}
/* Retire the stagger once it has played, or every later hover lags forever.
   Matches the specificity of the nth-child rules above. */
.in.done .rise:nth-child(1),.in.done .rise:nth-child(2),.in.done .rise:nth-child(3),
.in.done .rise:nth-child(4),.in.done .rise:nth-child(5),.in.done .rise:nth-child(6){transition-delay:0ms}

/* ---------- Motion off ---------------------------------------------------- */
body.paused *,body.paused *::before,body.paused *::after{animation-play-state:paused!important}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;transition-delay:0ms!important;
  }
  .rise{opacity:1;transform:none}
  .shot{clip-path:inset(0 0 0 0)}
}

/* ---- The name, resolved --------------------------------------------------
   Hover or focus a child and their letters light in the word. Done with
   :has() and no script, so the default state is the whole story and nothing
   here can fail to a broken block. */
.name-origin{margin-top:clamp(44px,5vw,72px);padding-top:clamp(32px,3.5vw,48px);border-top:1px solid var(--rule)}
.nm{margin-top:clamp(22px,2.4vw,32px)}
.nm-src{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:8px clamp(22px,3vw,44px)}
.nm-name{appearance:none;background:none;border:0;padding:6px 0;cursor:pointer;font-family:var(--display);font-size:clamp(1.5rem,3.4vw,2.25rem);line-height:1.15;color:var(--ink);letter-spacing:-.01em}
.nm-name .off{color:var(--mist)}
.nm-name:focus-visible{outline:2px solid var(--accent);outline-offset:4px;border-radius:3px}
.nm-word{margin:clamp(20px,2.6vw,34px) 0 0;font-family:var(--display);font-weight:600;font-size:clamp(2.75rem,9vw,6rem);line-height:1;letter-spacing:-.02em;color:var(--ink)}
.nm-word span{transition:opacity .28s var(--ease),color .28s var(--ease)}
.nm-i{color:var(--accent)}
/* tap, then tap off: the button releases focus so the word returns whole */
.nm-hint{margin:14px 0 0;font-family:var(--mono);font-size:.6875rem;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-3)}
.nm-why{margin-top:clamp(26px,3vw,38px);display:grid;gap:14px;max-width:62ch;font-size:.938rem;line-height:1.68;color:var(--ink-2)}
.nm-why b{font-weight:600;color:var(--ink)}

/* ---- the mark, at the end of the story that explains it ----------------
   The symbol is a T in Armenian, and the paragraph above it is the only
   place on the site that makes that mean anything; anywhere else it is a
   shape in a tab. Weight 13.58 here, matching the wordmark's stem, because
   it sits beside running text rather than standing alone. .nm-why is a
   grid with its own 14px gap, so this only adds the difference.         */
.nm-mark{display:flex;flex-wrap:wrap;align-items:center;gap:clamp(16px,2.4vw,28px);
  margin-top:clamp(8px,1.4vw,16px);padding-top:clamp(19px,2.4vw,26px);
  border-top:1px solid var(--rule-2)}
.nm-mark svg{flex:none;width:auto;height:clamp(50px,6.6vw,68px);color:var(--ink)}
.nm-mark p{margin:0;font-size:.938rem;line-height:1.55;color:var(--ink-2);max-width:38ch}

/* ---- the mark draws itself, once the letters have landed ---------------
   It is one unbroken stroke, which is the same property as the positioning:
   one practice, no handoffs. Three elements, but they meet end to end. The
   arch's right leg finishes at the bowl's three o'clock, which is exactly
   where an SVG circle begins, and the arm leaves from inside the bowl.
   pathLength="1" normalises the dash maths; the durations are proportional
   to the real lengths (202.08 / 145.83 / 49.62 units) and the timing is
   linear throughout, so the speed is genuinely constant across both joins.
   That constant speed is the whole point: a varying one would read as three
   strokes. Hooked to .play, so it replays on re-entry like the letters. */
/* Lengths are getTotalLength() from the browser: 202.10, 144.89, 49.62.
   pathLength="1" was ignored here, so stroke-dasharray:1 meant one user
   unit and the mark rendered as a row of hairline dashes. Explicit lengths
   instead, and the base state is HIDDEN: drawn-by-default meant the
   finished mark showed for a frame and then snapped back to redraw. */
.nm-mark .d1{stroke-dasharray:203;stroke-dashoffset:203}
.nm-mark .d2{stroke-dasharray:146;stroke-dashoffset:146}
.nm-mark .d3{stroke-dasharray:50;stroke-dashoffset:50}
.name-origin.play .nm-mark .d1{animation:drawMark .764s linear 2.30s forwards}
.name-origin.play .nm-mark .d2{animation:drawMark .548s linear 3.064s forwards}
.name-origin.play .nm-mark .d3{animation:drawMark .188s linear 3.612s forwards}
@keyframes drawMark{to{stroke-dashoffset:0}}
/* without motion, and if .play never fires, the mark simply is */
@media(prefers-reduced-motion:reduce){
  .nm-mark .d1,.nm-mark .d2,.nm-mark .d3{stroke-dashoffset:0}
  .name-origin.play .nm-mark .d1,.name-origin.play .nm-mark .d2,
  .name-origin.play .nm-mark .d3{animation:none}
}
/* the pairing: a child is held, everyone else steps back */
.nm:has(.nm-name[data-who="t"]:hover) .nm-word span:not([data-from~="t"]),
.nm:has(.nm-name[data-who="t"]:focus) .nm-word span:not([data-from~="t"]),
.nm:has(.nm-name[data-who="a"]:hover) .nm-word span:not([data-from~="a"]),
.nm:has(.nm-name[data-who="a"]:focus) .nm-word span:not([data-from~="a"]),
.nm:has(.nm-name[data-who="n"]:hover) .nm-word span:not([data-from~="n"]),
.nm:has(.nm-name[data-who="n"]:focus) .nm-word span:not([data-from~="n"]){opacity:.16}
.nm:has(.nm-name:hover) .nm-hint,.nm:has(.nm-name:focus) .nm-hint{opacity:0}
.nm-hint{transition:opacity .3s var(--ease)}
/* built once, as the section arrives */
.name-origin.play .nm-src li{animation:nmUp .6s var(--ease) backwards}
.name-origin.play .nm-src li:nth-child(1){animation-delay:.10s}
.name-origin.play .nm-src li:nth-child(2){animation-delay:.30s}
.name-origin.play .nm-src li:nth-child(3){animation-delay:.50s}
.name-origin.play .nm-word span{animation:nmUp .5s var(--ease) backwards;animation-delay:calc(.80s + var(--i) * .07s)}
.name-origin.play .nm-i{animation:nmUp .5s var(--ease) backwards,nmGold .7s var(--ease) 1.75s backwards;animation-delay:calc(.80s + var(--i) * .07s),1.75s}
@keyframes nmUp{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
@keyframes nmGold{from{color:var(--ink)}to{color:var(--accent)}}
@media (prefers-reduced-motion:reduce){
  .name-origin.play .nm-src li,.name-origin.play .nm-word span,.name-origin.play .nm-i{animation:none}
  .nm-i{color:var(--accent)}
}
@media(max-width:560px){.nm-src{gap:2px 20px}}



/* ============================================================================
   v3  Repositioning, Sept 2026
   Threshold positioning, teal mid-tone, and a looser hero.
   The palette had no usable mid-tone: navy L*24, then nothing until L*66.
   --teal at L*45 fills it. Cream on teal is 4.80:1, sand on teal is 4.08,
   so body copy on a teal band is cream. Bronze on teal is 1.08 and invisible.
   ========================================================================= */

/* ---- a fifth ground -------------------------------------------------- */
.sec-teal{background:var(--teal);color:var(--canvas)}
.sec-teal h2,.sec-teal h3{color:var(--canvas)}
.sec-teal .lede,.sec-teal p{color:#E8EEF0}
.sec-teal .eyebrow{color:#C9DDE2}
.sec-teal .rule{border-color:rgba(244,241,234,.30)}
.sec-teal .lnum{color:#C9DDE2;opacity:.9}
.sec-teal .lrow{border-top-color:rgba(244,241,234,.22)}

/* ---- one emphasised word, with Fraunces' wonk switched on ------------ */
.hero h1 em,.sec h2 em{
  font-style:italic;
  font-variation-settings:"SOFT" 60,"WONK" 1;
  font-weight:600;
  color:var(--accent-hi);
  padding-inline:.02em;
}
.sec-deep h2 em,.sec-teal h2 em{color:var(--accent-dk)}


/* ---- the lit cell in a three-up ---------------------------------------- */
.cell-lit{position:relative}
.sec-deep .cell-lit{background:rgba(159,180,190,.10);border-radius:3px;
  padding:clamp(18px,2.2vw,26px);margin:calc(-1 * clamp(18px,2.2vw,26px));
  outline:1px solid rgba(159,180,190,.22)}
.sec-deep .cell-lit .cell-tag{color:var(--accent-dk)}

/* ---- the handoffs ------------------------------------------------------ */
.handoffs{--ho-gap:clamp(12px,1.6vw,20px);display:grid;
  grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  gap:var(--ho-gap);margin-top:clamp(28px,3.4vw,44px)}
.ho{padding:20px 20px 22px;border-radius:3px;background:var(--canvas-2);
  border:1px solid var(--rule)}
.ho-who{font-family:var(--mono);font-size:.6875rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3);margin:0 0 9px}
.ho-what{font-size:.906rem;line-height:1.5;color:var(--ink-2);margin:0}
.ho-us{background:var(--teal);border-color:var(--teal)}
.ho-us .ho-who{color:#C9DDE2}
.ho-us .ho-what{color:var(--canvas)}

/* ---- practice note ----------------------------------------------------- */
.prac-note{margin:6px 0 0;font-size:.844rem;line-height:1.5;color:var(--ink-3);
  border-left:2px solid var(--accent);padding-left:13px}

/* ---- the optional fifth step ------------------------------------------- */
.lrow-opt .lnum{opacity:.55}
.lrow-opt h3::after{content:"optional";margin-left:10px;font-family:var(--mono);
  font-size:.594rem;letter-spacing:.12em;text-transform:uppercase;
  color:#C9DDE2;border:1px solid rgba(244,241,234,.34);padding:3px 7px;border-radius:2px;
  vertical-align:middle;font-weight:400}



/* ---- founder byline ---------------------------------------------------
   The practice is one person, and someone arriving from a referral wants to
   see that. At 46px it reads as a signature rather than as a portrait, which
   keeps the work in the lead position and off a personal-brand page. */
.byline{display:flex;align-items:center;gap:13px;margin:clamp(26px,3vw,36px) 0 0;
  padding-top:clamp(20px,2.4vw,26px);border-top:1px solid var(--rule);max-width:44ch}
.byline img{width:46px;height:46px;border-radius:50%;object-fit:cover;flex:none;
  background:var(--panel);box-shadow:0 2px 6px rgba(22,48,62,.16)}
.byline span{font-size:.844rem;line-height:1.45;color:var(--ink-3)}
.byline b{display:block;font-family:var(--display);font-variation-settings:"SOFT" 0,"WONK" 0;
  font-weight:600;font-size:.97rem;letter-spacing:-.005em;color:var(--ink);margin-bottom:1px}



/* ============================================================================
   Photographic hero, 22 Sept 2026
   Hero (03). Measured, the left field runs Y 0.212 to 0.832 because a light
   shaft crosses it, so it is a LIGHT ground, not a dark one: cream type on it
   is 1.00 to 3.38 and fails everywhere, navy is 2.92 to 9.83 and fails only
   in the brightest part of the shaft. Hence a cream scrim rather than a navy
   one, lifting the field to an even tone so navy type reads 7.9:1 to 9.9:1
   across the whole block instead of collapsing where the light lands.
   ========================================================================= */
.hero-photo{position:relative;isolation:isolate;padding:0;
  background:var(--canvas);color:var(--ink);overflow:hidden}
.hero-bg{position:absolute;inset:0;z-index:0}
.hero-bg img{width:100%;height:100%;object-fit:cover;object-position:76% 22%;display:block}
.hero-scrim{position:absolute;inset:0;
  background:linear-gradient(97deg,rgba(244,241,234,.90) 0%,rgba(244,241,234,.84) 30%,rgba(244,241,234,.52) 50%,rgba(244,241,234,.14) 66%,rgba(244,241,234,0) 80%)}
.hero-inner{position:relative;z-index:1;
  min-height:clamp(520px,64vh,690px);display:flex;flex-direction:column;justify-content:center;
  padding-block:clamp(56px,8vw,96px)}
.hero-photo .hero-copy{max-width:min(52ch,56%)}
.hero-photo .eyebrow{color:var(--accent-text)}
.hero-photo h1{color:var(--ink);max-width:17ch}
.hero-photo h1 em{color:var(--accent-hi)}
.hero-photo .lede{color:var(--ink);max-width:48ch;margin-top:20px}
.hero-photo .btn-row{margin-top:30px}
.hero-credit{position:relative;z-index:1;margin:clamp(22px,3vw,34px) 0 0;
  font-family:var(--mono);font-size:.6875rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-3)}

/* ---- the proof strip, directly under the hero --------------------------- */
.proofstrip{background:var(--canvas);position:relative;z-index:3}
.ps-row{position:relative;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));
  gap:2px;background:var(--rule);text-decoration:none}
.ps-row figure{margin:0;overflow:hidden;background:var(--panel);position:relative;z-index:1}
.ps-row img{display:block;width:100%;height:auto;aspect-ratio:1;object-fit:cover;
  transition:transform .8s var(--ease)}
.ps-row:focus-visible{outline:2px solid var(--accent);outline-offset:-3px}
.ps-tag{position:absolute;left:50%;bottom:0;transform:translate(-50%,50%);z-index:3;
  font-family:var(--mono);font-size:.6875rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--accent-hi);background:var(--canvas);padding:8px 16px;border-radius:2px;
  box-shadow:0 2px 10px rgba(22,48,62,.14);white-space:nowrap}

/* A 2.33:1 photograph cropped into a tall phone hero shows a vertical slice of
   a face and nothing else. Below 860px the image becomes its own band at its
   own aspect, with the type underneath it on plain canvas. */
@media(max-width:860px){
  .hero-photo{display:flex;flex-direction:column}
  .hero-bg{position:relative;inset:auto;width:100%;aspect-ratio:2.33/1;max-height:42vh;flex:none}
  .hero-bg img{object-position:72% 26%}
  .hero-scrim{background:linear-gradient(180deg,rgba(244,241,234,0) 62%,rgba(244,241,234,.55) 88%,rgba(244,241,234,.96) 100%)}
  .hero-inner{min-height:0;padding-block:clamp(20px,5vw,30px) clamp(34px,7vw,50px);justify-content:flex-start}
  .hero-photo .hero-copy{max-width:none}
  .hero-photo h1{max-width:none}
  .hero-credit{margin-top:clamp(18px,4vw,26px)}
  .ps-row{grid-template-columns:repeat(3,minmax(0,1fr))}
  .ps-row figure:nth-child(n+4){display:none}
  .ps-tag{font-size:.563rem;padding:7px 12px}
}

/* At 375px the band above is 375x161 and its 2.33/1 matches the file's own
   2400x1028 exactly, so cover fits the whole frame and object-position does
   nothing: she ends up small and right of centre with a lot of empty wall.
   Breaking the aspect match is what lets the crop bite. At 3/2 the image
   scales to 584 wide against a 375 window, so 209px of the left wall is cut
   and the X position finally has something to move. Phones only; the wide
   band is right on a tablet. */
@media(max-width:560px){
  .hero-bg{aspect-ratio:3/2;max-height:46vh}
  .hero-bg img{object-position:86% 50%}
}
@media(prefers-reduced-motion:reduce){.ps-row img{transition:none}}


/* ---- a light that follows the cursor, slowly -----------------------------
   Lifted in behaviour, not technique, from a WebGL hero that passes the pointer
   into a shader. No shader and no library here: JS eases two custom properties
   and CSS paints a warm radial with them.

   It is NOT on the hero, and that was measured rather than guessed. The hero is
   a light photograph under a cream scrim with navy type at about 9:1. Lightening
   that ground raises contrast but is invisible; darkening it is visible but
   drops the type toward the floor. Safe and visible are opposite directions
   there, so the effect has no room.

   On the navy ground it has plenty: cream on --deep is 10.21:1, and the glow at
   full strength only lifts the ground to roughly 6.8:1. Visible, and still two
   points clear of AA.                                                        */
.has-glow{position:relative;isolation:isolate;overflow:hidden;--lx:50%;--ly:38%}
.has-glow > .wrap{position:relative;z-index:1}
.glow{
  position:absolute;inset:0;z-index:0;pointer-events:none;
  background:radial-gradient(38vw 30vw at var(--lx) var(--ly),
    rgba(199,154,85,.20) 0%,
    rgba(159,180,190,.10) 34%,
    rgba(159,180,190,.03) 56%,
    rgba(159,180,190,0) 72%);
}
@media(prefers-reduced-motion:reduce){.glow{display:none}}
@media(hover:none){.glow{display:none}}


/* ---- the ring: one cursor companion, every ground -----------------------
   A glow only works on a dark ground, so it cannot be the site-wide gesture.
   An object that travels works on anything, and a hairline ring joins a
   language this site already speaks: every section head has a rule under it.

   It trails rather than tracks. Same 0.045 lerp as the glow, so the ring
   arrives about a second after the pointer. Its colour comes from whichever
   ground it is currently over, set per section below and read by the script. */
#ring{
  position:fixed;top:0;left:0;z-index:90;pointer-events:none;
  width:26px;height:26px;margin:-13px 0 0 -13px;border-radius:50%;
  border:1px solid var(--ring-ink,var(--accent));
  opacity:0;
  transition:width .38s var(--ease),height .38s var(--ease),
             margin .38s var(--ease),opacity .3s var(--ease),
             background-color .38s var(--ease),border-color .5s linear;
  will-change:transform;
}
#ring.awake{opacity:.55}
#ring.over{
  width:56px;height:56px;margin:-28px 0 0 -28px;opacity:.85;
  background:color-mix(in srgb,var(--ring-ink,var(--accent)) 9%,transparent);
}
/* which ink on which ground */
.sec-cream,.sec-paper,.hero-photo,.proofstrip{--ring-ink:var(--accent)}
.sec-deep,.sec-teal{--ring-ink:var(--accent-dk)}

@media(prefers-reduced-motion:reduce){#ring{display:none}}
@media(hover:none),(pointer:coarse){#ring{display:none}}


/* ============================================================================
   Motion, second pass. 23 Sept 2026.
   The fault was never too little motion. It was ninety elements performing one
   gesture. Text now lifts a short distance quickly, images wipe, cards settle
   out of a tilt, ledger numbers slide, and the hero has a load of its own.
   One rule holds all of it: things land. Nothing floats and nothing drifts.
   ========================================================================= */

/* ---- 1. the hero, orchestrated ----------------------------------------
   Above the fold, so it runs on load rather than waiting for an observer.
   fill-mode is backwards, never both: both pins the keyframe value
   permanently and outranks the stylesheet, which has cost this project a
   morning before. */
@keyframes heroLand{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
@keyframes heroSettle{from{transform:scale(1.045)}to{transform:scale(1)}}

.hero-photo .hero-copy > *,
.hero-photo .hero-credit{
  animation:heroLand 1.05s var(--ease) backwards;
}
.hero-photo .eyebrow     {animation-delay:.14s}
.hero-photo h1           {animation-delay:.34s}
.hero-photo .lede        {animation-delay:.68s}
.hero-photo .btn-row     {animation-delay:.88s}
.hero-photo .hero-credit {animation-delay:1.12s}
.hero-bg img{animation:heroSettle 3.4s var(--ease) backwards}

/* ---- 2. the proof strip arrives, left to right -------------------------
   Five pieces of client work landing in sequence. This gesture is the whole
   argument of the practice, so it gets its own and a slower beat. */

/* ---- 3a. cards settle out of the tilt they already hold ----------------- */

/* ---- 3b. the ledger numbers slide in from their own margin -------------- */
.lnum{transform:translateX(-14px);opacity:0;
  transition:transform .9s var(--ease),opacity .7s var(--ease)}
.in .lnum{transform:none;opacity:.85}
.sec-teal .in .lnum,.in .lrow .lnum{opacity:.9}
.lrow:nth-child(1) .lnum{transition-delay:60ms}
.lrow:nth-child(2) .lnum{transition-delay:180ms}
.lrow:nth-child(3) .lnum{transition-delay:300ms}
.lrow:nth-child(4) .lnum{transition-delay:420ms}
.lrow:nth-child(5) .lnum{transition-delay:540ms}

/* ---- 5a. the accordions actually open ----------------------------------
   Native details snaps. interpolate-size lets height animate to auto; where
   it is unsupported the panel simply appears, which is the old behaviour. */
:root{interpolate-size:allow-keywords}
.faq details::details-content{
  height:0;overflow:hidden;
  transition:height .4s var(--ease),content-visibility .4s allow-discrete;
}
.faq details[open]::details-content{height:auto}
.faq summary{transition:color .25s var(--ease)}
.faq summary:hover{color:var(--accent-hi)}

/* ---- 5b. buttons move, not just recolour -------------------------------- */
.btn{transition:background-color .3s var(--ease),border-color .3s var(--ease),
     color .3s var(--ease),transform .22s var(--ease)}
.btn:hover{transform:translateY(-1px)}
.btn:active{transform:translateY(0)}

@media(prefers-reduced-motion:reduce){
  .hero-photo .hero-copy > *,.hero-photo .hero-credit,.hero-bg img,
  .ps-row figure,.in .ps-row figure,.ps-row.in figure{animation:none;opacity:1;transform:none}
  .lnum{transform:none;opacity:.85}
  .faq details::details-content{transition:none}
  .btn:hover{transform:none}
}


/* ---- the proof strip, reworked -------------------------------------------
   They land together rather than one by one: five pieces of the same argument
   arriving as one statement.

   Landing is a transition, not a keyframe animation, and that matters. A
   filled animation keeps applying its final transform forever and outranks
   normal declarations, so an animated landing silently ate the hover scale.
   Transitions sit in the normal cascade and hand over cleanly.

   On hover the frame grows past the strip and the photograph inside it zooms
   too, so the picture gains more than the frame does. The strip carries
   z-index 3 so a grown frame passes over the navy section below rather than
   being painted over, which was also what cut the caption in half.

   transform-origin is pinned per position, or the outer two grow off the edge
   of the page and open a horizontal scrollbar.                              */
.ps-row{overflow:visible}
.ps-row figure{
  opacity:0;transform:translateY(24px) scale(.98);
  transition:opacity .9s var(--ease),transform .9s var(--ease),box-shadow .5s var(--ease);
  transform-origin:center center;
}
.ps-row figure:nth-child(1){transform-origin:left center}
.ps-row figure:nth-child(5){transform-origin:right center}
.ps-row img{transition:transform .65s var(--ease)}

.in .ps-row figure,.ps-row.in figure{opacity:1;transform:none}

/* after the landing rule, so it wins at equal specificity */
.in .ps-row figure:hover,.ps-row.in figure:hover{
  transform:scale(1.22);
  z-index:5;
  transition-duration:.5s;
  box-shadow:0 22px 48px -18px rgba(22,48,62,.48),0 4px 12px rgba(22,48,62,.16);
}
.ps-row figure:hover img{transform:scale(1.12)}

@media(prefers-reduced-motion:reduce){
  .ps-row figure{opacity:1;transform:none;transition:none}
  .ps-row img{transition:none}
  .in .ps-row figure:hover,.ps-row.in figure:hover{transform:none;box-shadow:none}
  .ps-row figure:hover img{transform:none}
}


/* ---- the handoffs: three wait, the fourth arrives -------------------------
   All four sit square. They used to carry half-degree tilts, which is the
   worst possible amount: too small to read as a deliberate scatter, large
   enough to read as a misalignment. Aline caught two of them. The only tilt
   left is on the teal card while it is travelling, where it reads as motion
   and resolves to zero on landing.

   The first three fade up on a short stagger. The teal card starts where the
   first one sits and travels the full width of the row, passing over all
   three, before settling into the fourth slot. Three describe the problem and
   then the answer crosses the whole page to take its place, which is the
   argument of the section made physical.

   Transitions, not keyframes. A filled animation keeps applying its final
   transform and outranks the hover rule, which is exactly what broke the
   proof strip. Learned once.

   Travel distance is exact rather than eyeballed: three card widths plus
   three gaps, hence the --ho-gap variable on the container.                 */
.handoffs .ho{
  opacity:0;
  transition:transform .85s var(--ease),opacity .7s var(--ease),
             box-shadow .55s var(--ease);
}
.ho:nth-child(1){transform:translateY(16px)}
.ho:nth-child(2){transform:translateY(16px)}
.ho:nth-child(3){transform:translateY(16px)}

/* the fourth starts in the first slot, lifted off the page, and above them all.
   Only where the row is actually four across: the grid is auto-fit at a 190px
   minimum, so it needs about 797px of track before it fits four, and below
   that the teal card wraps onto its own line. Travelling three card widths
   left from a row it is alone on would be nonsense, so under 940px it simply
   rises with the others. */
.handoffs .ho-us{position:relative;z-index:4;transform:translateY(16px)}
@media(min-width:940px){
  .handoffs .ho-us{
    transform:translateX(calc(-300% - (3 * var(--ho-gap)))) rotate(-3deg) scale(1.04);
    box-shadow:0 26px 54px -20px rgba(22,48,62,.5);
    transition:transform 1.25s cubic-bezier(.62,.03,.2,1),opacity .5s var(--ease),
               box-shadow .8s var(--ease);
  }
}

/* landed */
.handoffs.in .ho{opacity:1}
.handoffs.in .ho:nth-child(1){transform:none;transition-delay:0ms}
.handoffs.in .ho:nth-child(2){transform:none;transition-delay:110ms}
.handoffs.in .ho:nth-child(3){transform:none;transition-delay:220ms}
.handoffs.in .ho-us{
  /* no scale: 1.5% overhung the row's top line by a pixel. It is the only
     filled card, which is prominence enough. */
  transform:none;
  box-shadow:0 2px 10px rgba(22,48,62,.10);
  transition-delay:330ms;
}
@media(min-width:940px){ .handoffs.in .ho-us{transition-delay:.42s} }

/* hover comes last so it wins at equal specificity, same as the proof strip */
.handoffs.in .ho:hover{
  transform:scale(1.065);
  z-index:6;
  transition-duration:.42s;
  transition-delay:0ms;
  box-shadow:0 20px 44px -18px rgba(22,48,62,.42),0 3px 10px rgba(22,48,62,.13);
}
.handoffs.in .ho-us:hover{transform:scale(1.075)}

@media(prefers-reduced-motion:reduce){
  .handoffs .ho,.handoffs .ho-us{opacity:1;transition:none;box-shadow:none}
  .handoffs .ho-us{transform:none}
  .ho:nth-child(1),.ho:nth-child(2),.ho:nth-child(3){transform:none}
  .handoffs.in .ho:hover{transform:none;box-shadow:none}
}

/* ---- the hinge line between the diagnosis and the four handoffs -------- */
.turn{margin-top:clamp(34px,4.4vw,52px)}
.turn .lede{max-width:46ch}

/* ---- the section's closing statement ----------------------------------
   Was a second .panel, identical chrome to the one above the handoffs.
   Two boxed asides bracketing the cards read as one device used twice,
   and the section ended on the same note it played in the middle.
   Unboxed it stops being an aside and becomes the ending; the extra
   size and air do the work the border was doing.                        */
.close{margin-top:clamp(48px,6vw,82px)}
.close .pull{font-size:clamp(1.72rem,1.12rem + 2.4vw,2.85rem);max-width:26ch}

/* ---- handoffs restated for the deep ground ----------------------------
   These cards were drawn for cream. Two things break on navy:
   canvas-2 slabs shout against it, and every shadow in the block above is
   rgba(22,48,62,...), which IS --deep, so over that ground it renders as
   precisely nothing. Colours follow the idioms already set for .panel,
   .cell-tag and .cell p on this ground; the shadows are pushed to black so
   they have somewhere darker to go. --teal stays, and reads harder here
   than it did on cream, which is the point of it.                        */
.sec-deep .ho{background:rgba(244,241,234,.05);border-color:var(--rule-dk)}
.sec-deep .ho-who{color:var(--accent-dk)}
.sec-deep .ho-what{color:var(--mist)}
.sec-deep .ho-us{background:var(--teal);border-color:var(--teal)}
.sec-deep .ho-us .ho-who{color:#C9DDE2}
.sec-deep .ho-us .ho-what{color:var(--canvas)}
@media(min-width:940px){
  .sec-deep .handoffs .ho-us{box-shadow:0 26px 54px -20px rgba(0,0,0,.62)}
}
.sec-deep .handoffs.in .ho-us{box-shadow:0 2px 12px rgba(0,0,0,.34)}
.sec-deep .handoffs.in .ho:hover{
  box-shadow:0 20px 44px -18px rgba(0,0,0,.64),0 3px 10px rgba(0,0,0,.3);
  border-color:var(--rule-dk-2);
}
@media(prefers-reduced-motion:reduce){
  .sec-deep .handoffs .ho,.sec-deep .handoffs .ho-us{box-shadow:none}
  .sec-deep .handoffs.in .ho:hover{box-shadow:none}
}


/* ---- iOS zoom on focus --------------------------------------------------
   Safari on iPhone zooms the whole page whenever a form control is focused at
   under 16px, and it does not zoom back out afterwards. Every control here
   computed to 15.008px, which is exactly the trap, and the contact form is the
   only conversion surface on the site. Pinned to 16px where it matters; the
   desktop size is left alone because the behaviour is iOS-only.            */
@media(max-width:860px){
  .field input,.field select,.field textarea{font-size:16px}
}


/* ---- the caption yields to whatever you are looking at -------------------
   It labels the whole strip, not one frame, so it neither travels with a
   frame nor sits on top of one. At rest it is above the row (z-index 3 over
   the frames' 1). A hovered frame goes to 5 and passes in front of it, and
   the caption fades back at the same time so it reads as giving way rather
   than being accidentally occluded.                                        */
.ps-tag{transition:opacity .38s var(--ease),transform .38s var(--ease)}
.ps-row:has(figure:hover) .ps-tag{
  opacity:0;
  transform:translate(-50%,50%) scale(.97);
}
@media(prefers-reduced-motion:reduce){
  .ps-tag{transition:none}
  .ps-row:has(figure:hover) .ps-tag{opacity:0;transform:translate(-50%,50%)}
}

/* ---- Longer answers: links to the notes, written onto index.html and work.html by
   build-notes.py. Plain text links on purpose: they are for people who want more,
   and for search engines that would otherwise only find the notes in the sitemap. */
.notes-more{margin-top:clamp(36px,4.5vw,56px);display:flex;flex-wrap:wrap;align-items:baseline;gap:12px 36px}
.notes-more .eyebrow{margin:0}
.notes-links{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:12px 32px}
