/* generated by tools/build.sh from tokens+base+components+sections+motion. Edit those. */
/* ---- tokens.css ---- */
/* zwornik — design tokens. Single source of truth for colour, type, grid, radius, motion, layers. */

/* ---- Fonts -------------------------------------------------------------- */
@font-face{font-family:"Switzer";src:url("/assets/fonts/Switzer-Light.woff2") format("woff2");font-weight:300;font-style:normal;font-display:swap}
@font-face{font-family:"Switzer";src:url("/assets/fonts/Switzer-Regular.woff2") format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Switzer";src:url("/assets/fonts/Switzer-Medium.woff2") format("woff2");font-weight:500;font-style:normal;font-display:swap}

/* Metrics-matched fallback: measured from Switzer-Regular against Arial, so the swap does not
   move a single baseline. x-height 0.5310 vs 0.5186 -> size-adjust 102.4%. */
@font-face{
  font-family:"Switzer Fallback";
  src:local("Helvetica Neue"),local("Arial"),local("Liberation Sans");
  size-adjust:102.40%; ascent-override:95.70%; descent-override:24.41%; line-gap-override:0%;
}

:root{
  color-scheme:light dark;

  --font-sans:"Switzer","Switzer Fallback","Helvetica Neue",Arial,system-ui,sans-serif;

  /* ---- Colour (light) --------------------------------------------------- */
  --ink:#1c1b19;
  --paper:#fbfaf7;
  --stage:#f3f2ee;
  --muted:#6f6d69;          /* darkened from the brief's #7a7874: see DECISIONS.md D5 (AA) */
  --accent:#9c4a2f;         /* terracotta, 54% saturation, 5.86:1 on --paper */
  --accent-ink:var(--paper);
  --accent-soft:color-mix(in oklab, var(--accent) 10%, var(--paper));
  --accent-line:color-mix(in oklab, var(--accent) 35%, transparent);
  --chip:#e8e6e1;
  --disc:#d8d6d1;
  --line:color-mix(in oklab, var(--ink) 15%, transparent);
  --line-strong:var(--ink);
  --skeleton:color-mix(in oklab, var(--ink) 5%, transparent);
  --scrim:linear-gradient(to top, rgb(28 27 25 / .55), transparent 60%);

  /* ---- Type roles: fluid clamp(), rem-floor and rem-ceiling, 390 -> 1440 -- */
  --t-display-xl:clamp(3rem, 1.143rem + 7.619vw, 8rem);
  --t-display-l: clamp(3rem, 2.257rem + 3.048vw, 5rem);
  --t-display-m: clamp(1.75rem, 1.1rem + 2.667vw, 3.5rem);
  --t-display-s: clamp(1.375rem, 1.05rem + 1.333vw, 2.25rem);
  --t-title:     clamp(1rem, .814rem + .762vw, 1.5rem);
  --t-label:     clamp(.875rem, .782rem + .381vw, 1.125rem);
  --t-body-l:    clamp(1rem, .954rem + .19vw, 1.125rem);
  --t-body-m:    1rem;
  --t-body-s:    .875rem;
  --t-tag:       clamp(.75rem, .704rem + .19vw, .875rem);
  --t-button:    clamp(.875rem, .829rem + .19vw, 1rem);
  --t-menu:      clamp(1rem, .954rem + .19vw, 1.125rem);
  --t-figure:    clamp(3rem, 2.257rem + 3.048vw, 5rem);

  --lh-display-xl:.92; --lh-display-l:1.05; --lh-display-m:1.02; --lh-display-s:1.24;
  --lh-title:1.2; --lh-label:1.2; --lh-body-l:1.5; --lh-body-m:1.4; --lh-body-s:1.3;
  --lh-tight:1;   --lh-figure:1.1;

  /* ---- Grid ------------------------------------------------------------- */
  --gutter:1rem;
  --cols:12;
  --max:1920px;

  /* ---- Radius (nothing outside this set) -------------------------------- */
  --r-media:.25rem;
  --r-panel:.5rem;
  --r-pill:100vmax;
  /* Bounded, not --r-pill: on a 161:412 pane an unbounded radius clamps to half the box and
     collapses the lozenge into a petal. --r-leaf-size is overridden per component. */
  --r-leaf-size:clamp(1.5rem, 2.6vw, 3rem);
  --r-leaf:var(--r-leaf-size) var(--r-media) var(--r-leaf-size) var(--r-media);

  /* ---- Spacing (4px scale) ---------------------------------------------- */
  --s-1:.25rem; --s-2:.5rem;  --s-3:.75rem; --s-4:1rem;   --s-6:1.5rem;
  --s-8:2rem;   --s-10:2.5rem; --s-12:3rem; --s-16:4rem;  --s-20:5rem;
  --s-23:5.75rem; --s-31:7.75rem; --s-35:8.75rem;

  /* ---- Motion ----------------------------------------------------------- */
  --ease-out:cubic-bezier(.25,.46,.45,.94);
  --ease-out-quart:cubic-bezier(.165,.84,.44,1);
  --ease-in-out:cubic-bezier(.455,.03,.515,.955);
  --d-feedback:.1s; --d-hover:.4s; --d-fill:.45s; --d-line:.7s; --d-sheet:.3s;
  --marquee-speed:60px;

  /* ---- Layers (documented scale; no ad-hoc z-index anywhere) ------------- */
  --z-base:0; --z-media:1; --z-nav:100; --z-overlay:200; --z-loader:300;

  --bar-h:4rem;
}

@media (min-width:1024px){
  :root{ --gutter:2rem; --cols:24; --bar-h:4.5rem; }
}

/* ---- Colour (dark) — same roles, no mid-page inversion anywhere ---------- */
@media (prefers-color-scheme:dark){
  :root{
    --ink:#f2f0eb;
    --paper:#141311;
    --stage:#1b1a17;
    --muted:#9c9994;
    --accent:#d9825f;       /* lifted for the dark ground, 62% saturation, 6.55:1 on --paper */
    --chip:#26241f;
    --disc:#2e2c27;
    --scrim:linear-gradient(to top, rgb(10 9 8 / .65), transparent 60%);
  }
}
/* ---- base.css ---- */
/* zwornik — reset, type roles, grid, global accessibility parities. */

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

html{
  -webkit-text-size-adjust:100%;
  text-size-adjust:100%;
  scroll-behavior:smooth;
  /* Sticky bar height + a little air, so #anchor targets are not hidden under it. */
  scroll-padding-top:calc(var(--bar-h) + 1rem);
}
@media (prefers-reduced-motion:reduce){ html{scroll-behavior:auto} }

body{
  background:var(--paper);
  color:var(--ink);
  font-family:var(--font-sans);
  font-size:var(--t-body-l);
  line-height:var(--lh-body-l);
  font-weight:400;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
  padding-left:env(safe-area-inset-left);
  padding-right:env(safe-area-inset-right);
}

img,picture,svg,video{display:block;max-width:100%}
/* must beat the rule above, or the inline icon sprite renders as a 300x150 block */
[hidden]{display:none!important}
img{height:auto;background:var(--skeleton)}
a{color:inherit;text-decoration:none}
button,input,textarea,select{font:inherit;color:inherit}
button{background:none;border:0;cursor:pointer}
ul,ol{list-style:none;padding:0}
::selection{background:var(--ink);color:var(--paper)}

/* Focus: one visible treatment, both themes, never removed. */
:focus-visible{outline:2px solid var(--line-strong);outline-offset:2px;border-radius:var(--r-media)}
:focus:not(:focus-visible){outline:none}

/* Tap highlight is managed, not left to the platform blue box. */
a,button,label,summary,[role="button"]{-webkit-tap-highlight-color:transparent}

.skip{
  position:absolute;left:var(--gutter);top:-100%;z-index:var(--z-loader);
  background:var(--ink);color:var(--paper);
  padding:.75rem 1rem;border-radius:var(--r-media);
  font-size:var(--t-button);font-weight:500;
  transition:top .2s var(--ease-out);
}
.skip:focus{top:.75rem}

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

/* ---- Type roles ---------------------------------------------------------- */
.t-display-xl{font-size:var(--t-display-xl);line-height:var(--lh-display-xl);font-weight:300;letter-spacing:-.02em}
.t-display-l {font-size:var(--t-display-l); line-height:var(--lh-display-l); font-weight:300;letter-spacing:-.015em}
.t-display-m {font-size:var(--t-display-m); line-height:var(--lh-display-m); font-weight:400;letter-spacing:-.01em}
.t-display-s {font-size:var(--t-display-s); line-height:var(--lh-display-s); font-weight:400;letter-spacing:-.005em}
.t-title     {font-size:var(--t-title);     line-height:var(--lh-title);     font-weight:400}
.t-label     {font-size:var(--t-label);     line-height:var(--lh-label);     font-weight:500}
.t-body-l    {font-size:var(--t-body-l);    line-height:var(--lh-body-l);    font-weight:400}
.t-body-m    {font-size:var(--t-body-m);    line-height:var(--lh-body-m);    font-weight:400}
.t-body-s    {font-size:var(--t-body-s);    line-height:var(--lh-body-s);    font-weight:400}
.t-tag       {font-size:var(--t-tag);       line-height:var(--lh-tight);     font-weight:500}
.t-figure    {font-size:var(--t-figure);    line-height:var(--lh-figure);    font-weight:300;font-variant-numeric:tabular-nums}

h1,h2,h3,h4,h5{text-wrap:balance;font-weight:inherit}
p{text-wrap:pretty}
.measure{max-width:65ch}
.lower{text-transform:lowercase}
.muted{color:var(--muted)}
.tnum{font-variant-numeric:tabular-nums}

/* ---- Grid ---------------------------------------------------------------- */
.grid{
  display:grid;
  grid-template-columns:repeat(var(--cols),minmax(0,1fr));
  column-gap:var(--gutter);
  width:calc(100% - 2 * var(--gutter));
  max-width:var(--max);
  margin-inline:auto;
}
/* Full-bleed background without leaving the grid. */
.bleed{position:relative;isolation:isolate}
.bleed::before{
  content:"";position:absolute;inset:0 calc(var(--gutter) * -1);
  z-index:-1;background:var(--bleed-fill,transparent);
}

/* ---- Section rhythm (DENSITY 3) ------------------------------------------ */
.section{padding-block:var(--s-6)}
@media (min-width:1024px){ .section{padding-block:var(--s-12)} }

/* ---- Media parities ------------------------------------------------------ */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important;
  }
}

@media (prefers-contrast:more){
  :root{--line:color-mix(in oklab, var(--ink) 55%, transparent);--muted:var(--ink)}
  .chip,.card-media,figure img{outline:1px solid var(--line-strong);outline-offset:-1px}
}

@media (forced-colors:active){
  :root{--line:CanvasText;--line-strong:CanvasText;--ink:CanvasText;--paper:Canvas}
  .btn{border:1px solid ButtonText!important;forced-color-adjust:none;background:ButtonFace!important;color:ButtonText!important}
  .btn__fill,.loader{display:none!important}
  .rule,.rule-strong{background:CanvasText!important;forced-color-adjust:none}
  :focus-visible{outline:2px solid Highlight}
}
/* ---- components.css ---- */
/* zwornik — components. One button, four variants; chips; wordmark logo; section header; cards;
   hairline rules; form fields. */

.icon{width:1em;height:1em;flex:none;fill:currentColor}

/* ---- Hairline rule ------------------------------------------------------- */
/* Rules are drawn with scale on a pseudo-element, never by animating a border. */
.rule{position:absolute;background:var(--line);transform-origin:top}
.rule--v{top:0;bottom:0;width:1px}
.rule--h{left:0;right:0;height:1px;transform-origin:left}
.rule--strong{background:var(--line-strong)}

/* ---- Button -------------------------------------------------------------- */
/* .btn is the hit target (>= 44px both axes); .btn__box is the visual pill, which is what
   overflow-clips the label roll and the fill. Keeping them separate is what lets a 2rem
   chip-sized button still meet R-A05 without a transparent outline around the visual. */
.btn{
  --btn-h:2.375rem;
  --btn-px:1rem;
  --btn-x:1.25rem;                       /* fill origin; buttons.js sets it to the icon centre */
  display:inline-flex;align-items:center;justify-content:center;
  min-height:2.75rem;min-width:2.75rem;
  font-size:var(--t-button);line-height:var(--lh-tight);font-weight:500;
  transition:scale var(--d-feedback) var(--ease-out);
}
.btn--sm{--btn-h:2rem;--btn-px:.5rem}
.btn--md{--btn-h:2.5rem}
.btn--lg{--btn-h:2.625rem}
.btn--xl{--btn-h:3rem}
.btn:active{scale:.982}

.btn__box{
  position:relative;isolation:isolate;overflow:hidden;
  display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
  height:var(--btn-h);min-width:var(--btn-h);
  padding-inline:var(--btn-px);
  border-radius:calc(var(--btn-h) / 2);
  transition:color var(--d-fill) var(--ease-out-quart);
}
.btn__icon{display:inline-flex;font-size:1.15em}
/* The label stretches to the full box height so both halves of the roll can travel exactly one
   button height. Both distances are `var(--btn-h)`, not a percentage: a percentage on the inner
   <span> resolves against the span's own line box (~16px) while the same percentage on ::after
   resolves against the stretched label, so the two halves moved at different speeds and on the
   48px xl button the outgoing label never cleared the clip - it parked as a sliver along the top
   edge and hover showed two labels at once. */
.btn__label{
  position:relative;display:grid;place-items:center;align-self:stretch;white-space:nowrap;
}
.btn__label > span{display:block;transition:translate var(--d-fill) var(--ease-out)}
/* The rolling duplicate. Presentational only: the real label is the inner <span>. */
.btn__label::after{
  content:attr(data-label);position:absolute;inset:0;display:grid;place-items:center;
  translate:0 var(--btn-h);transition:translate var(--d-fill) var(--ease-out);
}
/* Divergence §4.4: the fill is a disc that opens from the icon, not a panel from the bottom. */
.btn__fill{
  position:absolute;inset:0;z-index:-1;
  clip-path:circle(0 at var(--btn-x) 50%);
  transition:clip-path var(--d-hover) var(--ease-out-quart);
}

.btn--outlined .btn__box{border:1px solid var(--ink)}
.btn--outlined .btn__fill{background:var(--ink)}
.btn--filled  .btn__box{background:var(--accent);color:var(--accent-ink)}
.btn--filled  .btn__fill{background:var(--accent-ink)}

@media (hover:hover) and (pointer:fine){
  .btn:hover .btn__label > span{translate:0 calc(-1 * var(--btn-h))}
  .btn:hover .btn__label::after{translate:0 0}
  .btn:hover .btn__fill{clip-path:circle(150% at var(--btn-x) 50%)}
  .btn--outlined:hover .btn__box{color:var(--paper)}
  .btn--filled:hover  .btn__box{color:var(--accent)}
}
/* Under reduced motion the roll and the fill are not animated; hover still reads via colour. */
@media (prefers-reduced-motion:reduce){
  .btn__label::after{display:none}
  .btn--outlined:hover .btn__box{background:var(--ink);color:var(--paper)}
  .btn--filled:hover .btn__box{background:var(--accent-ink);color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
}

/* Text variant: no box, underline fades in. */
.btn--text{min-height:2.75rem}
.btn--text .btn__box{padding-inline:0;border-radius:0;gap:.4rem}
.btn--text .btn__label{align-self:auto}
.btn--text .btn__label::after{display:none}
.btn--text .btn__label > span{transition:none}
.btn--text .btn__label{padding-bottom:.15rem;background-image:linear-gradient(var(--line-strong),var(--line-strong));
  background-size:100% 1px;background-repeat:no-repeat;background-position:0 100%;
  opacity:1;transition:opacity var(--d-hover) var(--ease-out)}
@media (hover:hover) and (pointer:fine){
  .btn--text .btn__label{opacity:.6}
  .btn--text:hover .btn__label{opacity:1}
}

/* ---- Chip ---------------------------------------------------------------- */
.chip{
  display:inline-flex;align-items:center;gap:.4rem;
  min-height:2rem;padding-inline:.75rem;
  border-radius:var(--r-pill);
  background:var(--chip);border:1px solid transparent;
  font-size:var(--t-tag);line-height:var(--lh-tight);font-weight:500;
  transition:background var(--d-hover) var(--ease-out),scale var(--d-feedback) var(--ease-out);
}
a.chip,button.chip{min-height:2.75rem}
/* F28/R-A05: min-height alone left the short filter chips ("all" = 39px wide) under the 44px
   target minimum on the short axis. Width only needs the floor where a finger is the pointer. */
@media (pointer:coarse){ a.chip,button.chip{min-width:2.75rem} }
button.chip:active,a.chip:active{scale:.982}
@media (hover:hover) and (pointer:fine){
  a.chip:hover,button.chip:hover{background:color-mix(in oklab,var(--ink) 15%,var(--chip))}
}
.chip[aria-pressed="true"]{background:var(--accent);color:var(--accent-ink)}

/* ---- Wordmark logo ------------------------------------------------------- */
/* Wordmark logo. A circled monogram reads as an avatar or an app icon; a company puts its
   name in the corner. Same hit target as the disc it replaces (>= 44px via .bar__logo). */
.wordmark-logo{
  display:inline-flex;align-items:center;min-height:2.75rem;
  color:var(--ink);text-decoration:none;
}
.wordmark-logo__mark{
  font-size:var(--t-title);line-height:1;font-weight:500;letter-spacing:-.01em;
  padding-bottom:.15rem;
  background-image:linear-gradient(var(--accent),var(--accent));
  background-size:0 1px;background-repeat:no-repeat;background-position:0 100%;
  transition:background-size var(--d-hover) var(--ease-out-quart);
}
a.wordmark-logo:active{scale:.982}
@media (min-width:1024px){ .wordmark-logo__mark{font-size:var(--t-display-s)} }
@media (hover:hover) and (pointer:fine){
  a.wordmark-logo:hover .wordmark-logo__mark{background-size:100% 1px}
}

/* ---- Section header ------------------------------------------------------ */
/* Title + a rule that eats the remaining width, so the statement is part of one header block
   instead of a floating right column. */
.sec-head{padding-block:var(--s-6);row-gap:var(--s-6)}
.sec-head__title{grid-column:1/-1;display:flex;align-items:center;gap:var(--s-8);max-width:16ch}
.sec-head__title::after{content:"";height:1px;min-width:2.5rem;flex:1;background:var(--line)}
.sec-head__body{grid-column:1/-1;margin-top:var(--s-6)}
.sec-head__cta{grid-column:1/-1;margin-top:var(--s-4);justify-self:start}
@media (min-width:1024px){
  .sec-head{padding-block:var(--s-12)}
  .sec-head__title{grid-column:1/span 8;max-width:none}
  .sec-head__body{grid-column:13/-3;margin-top:0;font-size:var(--t-display-s);line-height:1.2}
  .sec-head__cta{grid-column:13/-1;margin-top:var(--s-6)}
}

/* ---- Card (feed + gallery) ----------------------------------------------- */
.card{display:block;position:relative}
.card__media{
  display:block;position:relative;overflow:hidden;border-radius:var(--r-media);
  margin-bottom:var(--s-4);background:var(--skeleton);aspect-ratio:4/3;
}
.card__media img{width:100%;height:100%;object-fit:cover}
@media (min-width:768px){ .card__media{aspect-ratio:16/9} }
.card--tall .card__media{aspect-ratio:3/4}
.card__tags{display:flex;flex-wrap:wrap;gap:.4rem;margin-bottom:.5rem}
.card__title{display:block;font-size:var(--t-body-m);line-height:var(--lh-body-m)}
.card__sub{display:block;color:var(--muted);font-size:var(--t-body-m);line-height:var(--lh-body-m)}
@media (hover:hover) and (pointer:fine){
  .card:hover .card__title{background-image:linear-gradient(currentColor,currentColor);
    background-size:100% 1px;background-repeat:no-repeat;background-position:0 100%}
}

/* ---- Form ---------------------------------------------------------------- */
.field{display:grid;gap:.4rem;margin-bottom:var(--s-6)}
.field label{font-size:var(--t-label);font-weight:500}
.field input,.field textarea{
  font-size:1rem;                                  /* >= 16px: no iOS zoom-on-focus */
  padding:.75rem;min-height:2.75rem;
  background:var(--paper);color:var(--ink);
  border:1px solid var(--line-strong);border-radius:var(--r-media);
}
.field textarea{min-height:8rem;resize:vertical}
.field input::placeholder,.field textarea::placeholder{color:var(--muted)}
.field__hint{font-size:var(--t-body-s);color:var(--muted)}
.field__error{font-size:var(--t-body-s);font-weight:500;display:none}
.field[data-invalid] .field__error{display:flex;align-items:center;gap:.35rem}
.field[data-invalid] input,.field[data-invalid] textarea{border-width:2px}
.field--check{grid-template-columns:auto 1fr;align-items:start;gap:.6rem}
.field--check input{min-height:1.25rem;width:1.25rem;height:1.25rem;margin-top:.15rem;accent-color:var(--ink)}
.field--check label{font-size:var(--t-body-s);font-weight:400;line-height:1.4}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
/* ---- sections.css ---- */
/* zwornik — shell (bar, menu, footer, loader) and page sections. */

/* =========================================================== TOP BAR ====== */
.bar{
  position:sticky;top:0;z-index:var(--z-nav);
  align-items:center;
  min-height:var(--bar-h);
  padding-top:max(.75rem,env(safe-area-inset-top));
  transition:translate var(--d-hover) var(--ease-out);
}
.bar::after{
  content:"";position:absolute;inset:0 calc(var(--gutter) * -1);z-index:-1;
  background:var(--paper);transition:background var(--d-hover) var(--ease-out);
}
.bar[data-stage]::after{background:var(--stage)}
.bar[data-hidden]{translate:0 -100%}
@media (min-width:1024px){ .bar{padding-top:max(1rem,env(safe-area-inset-top))} }

.bar__logo{grid-column:1/span 3;justify-self:start}
.bar__menu{grid-column:-4/-1;justify-self:end}
@media (min-width:1024px){ .bar__logo{grid-column:1/span 2} .bar__menu{grid-column:-3/-1} }

/* Inline nav: the hairline is the state. Baselines never move (brief §4.6). */
.nav{display:none}
@media (min-width:1024px){
  .nav{display:grid;grid-template-columns:repeat(4,1fr);grid-column:7/span 15;align-self:stretch}
}
@media (min-width:1280px){ .nav{grid-column:12/span 11} }
.nav__link{
  position:relative;display:flex;align-items:center;
  min-height:2.75rem;padding-left:.75rem;
  font-size:var(--t-menu);line-height:var(--lh-tight);
  transition:color var(--d-hover) var(--ease-out);
}
.nav__link::before,.nav__link::after{
  content:"";position:absolute;left:0;top:calc(var(--bar-h) * -1);bottom:0;width:1px;
}
.nav__link::before{background:var(--line)}
.nav__link::after{
  background:var(--accent);scale:1 0;transform-origin:bottom;
  transition:scale var(--d-hover) var(--ease-out);
}
.nav__link[aria-current]::after,
.nav__link:focus-visible::after{scale:1 1}
@media (hover:hover) and (pointer:fine){ .nav__link:hover::after{scale:1 1} }
/* At the very top of the page the active rule runs 1.5x, tying the bar to the hero stage. */
.bar[data-top] .nav__link[aria-current]::after{bottom:-50%}
.nav:has([aria-current]) .nav__link:not([aria-current]){color:var(--muted)}

/* Inner pages below 1024 get the nav as a scroller; the home page does not (the hero carries it). */
.nav-scroll{
  grid-column:1/-1;display:flex;gap:.5rem;overflow-x:auto;
  scrollbar-width:none;margin-top:var(--s-3);padding-bottom:var(--s-2);
}
.nav-scroll::-webkit-scrollbar{display:none}
@media (min-width:1024px){ .nav-scroll{display:none} }

/* ============================================================= MENU ======= */
.menu{position:fixed;inset:0;z-index:var(--z-overlay);visibility:hidden}
.menu[data-open]{visibility:visible}
.menu__backdrop{position:absolute;inset:0;background:rgb(0 0 0 / .5);opacity:0;
  transition:opacity var(--d-sheet) var(--ease-out)}
.menu__sheet{
  position:absolute;inset:0;height:100dvh;overflow-y:auto;overscroll-behavior:contain;
  background:var(--paper);
  padding:max(1rem,env(safe-area-inset-top)) var(--gutter) max(2rem,env(safe-area-inset-bottom));
  opacity:0;transition:opacity var(--d-sheet) var(--ease-out);
  display:grid;grid-template-columns:1fr;align-content:start;gap:var(--s-8);
}
.menu[data-open] .menu__backdrop,.menu[data-open] .menu__sheet{opacity:1}
@media (min-width:1024px){
  .menu__sheet{
    grid-template-columns:7fr 4fr 13fr;
    grid-template-rows:3.5rem 8fr minmax(10rem,1fr);
    grid-template-areas:"logo media top" "monogram media nav" "tagline media socials";
    column-gap:var(--s-8);row-gap:var(--s-6);
    padding-inline:var(--gutter);align-content:stretch;
  }
  .menu__logo{grid-area:logo} .menu__monogram{grid-area:monogram;align-self:center}
  .menu__tagline{grid-area:tagline;align-self:end} .menu__media{grid-area:media;align-self:center}
  .menu__nav{grid-area:nav;align-self:center} .menu__socials{grid-area:socials;align-self:end}
  .menu__top{grid-area:top;justify-self:end}
}
.menu__logo svg{width:9rem}
.menu__monogram svg{width:6rem}
@media (min-width:1024px){ .menu__monogram svg{width:11rem} }
.menu__media{max-width:9.9375rem;margin-inline:auto;width:100%}
.menu__media img{width:100%;aspect-ratio:161/412;object-fit:cover;border-radius:var(--r-leaf)}
@media (max-width:1023px){
  .menu__media{max-width:8.125rem}
  /* Drifts with the sheet's own scroll. No JS, no listener. */
  @supports (animation-timeline:scroll()){
    .menu__media img{animation:drift linear both;animation-timeline:scroll(nearest);}
  }
}
@keyframes drift{ from{translate:0 -2rem} to{translate:0 2rem} }

.menu__list{display:grid;gap:.25rem}
.menu__link{
  position:relative;display:block;padding-left:1rem;padding-block:.35rem;
  font-size:var(--t-display-m);line-height:var(--lh-display-m);font-weight:400;
}
.menu__link::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:1px;background:var(--accent);
  scale:1 0;transform-origin:top;transition:scale var(--d-line) var(--ease-out-quart);
}
.menu__link[aria-current]::before{scale:1 1}
@media (hover:hover) and (pointer:fine){ .menu__link:hover::before{scale:1 1} }
.menu__chips{display:flex;flex-wrap:wrap;gap:.4rem;padding-left:1rem;margin-block:.5rem 1rem}
.menu__socials{display:grid;gap:.75rem;align-content:end}
.menu__social-row{display:flex;flex-wrap:wrap;gap:1.25rem}

.lang{display:inline-flex;gap:.5rem;align-items:center;font-size:var(--t-body-s)}
.lang__on,.lang__off{padding-bottom:.15rem;border-bottom:1px solid var(--line)}
.lang__on{border-bottom-color:var(--line-strong)}
.lang__off{color:var(--muted)}

/* Staggered entry. Collapses to the plain fade above under reduced motion. */
.menu[data-open] .menu__stagger > *{animation:rise .5s var(--ease-out-quart) both}
.menu__stagger > *:nth-child(1){animation-delay:.18s}
.menu__stagger > *:nth-child(2){animation-delay:.24s}
.menu__stagger > *:nth-child(3){animation-delay:.30s}
.menu__stagger > *:nth-child(4){animation-delay:.36s}
.menu__stagger > *:nth-child(5){animation-delay:.42s}
.menu__stagger > *:nth-child(6){animation-delay:.48s}
@keyframes rise{ from{opacity:0;translate:0 1rem} to{opacity:1;translate:0 0} }

/* ============================================================ LOADER ====== */
.loader{
  position:fixed;inset:0;z-index:var(--z-loader);
  display:grid;place-content:center;justify-items:center;gap:1rem;
  background:var(--stage);color:var(--ink);
  transition:opacity .4s var(--ease-out),visibility .4s;
}
.loader svg{width:3rem}
.loader[data-done]{opacity:0;visibility:hidden}
@media (prefers-reduced-motion:reduce){ .loader{display:none} }

/* ============================================================== HERO ====== */
.hero{position:relative;padding-bottom:var(--s-20)}
.hero::before{
  content:"";position:absolute;inset:calc(var(--bar-h) * -1) calc(var(--gutter) * -1) 0;
  z-index:-1;background:var(--stage);
}
@media (min-width:1024px){
  .hero{height:calc(100dvh - var(--bar-h));padding-bottom:0;align-content:center}
}

.hero__wordmark{
  grid-column:1/-1;grid-row:1;align-self:center;justify-self:center;
  width:100%;pointer-events:none;color:var(--ink);
}
@media (min-width:1024px){ .hero__wordmark{z-index:var(--z-media)} }
.hero__wordmark svg{width:100%;height:auto;max-height:26vh;margin-inline:auto}
@media (min-width:1024px){ .hero__wordmark{grid-column:2/14} }
@media (min-width:1280px){ .hero__wordmark{grid-column:5/17} }
/* Divergence §4.3: the mark rises out of a vertical clip; the tail then fades to the monogram. */
.hero__wordmark .wm-tail{transition:opacity .8s var(--ease-out)}

.hero__panes{
  grid-column:1/-1;grid-row:2;align-self:center;margin-top:var(--s-8);
  display:grid;grid-template-columns:repeat(3,1fr);column-gap:var(--gutter);
  position:relative;
}
@media (min-width:1024px){ .hero__panes{grid-column:7/span 15;grid-row:1;margin-top:0} }
@media (min-width:1280px){ .hero__panes{grid-column:12/span 11} }

.pane{position:relative;display:block;padding-inline:.5rem}
.pane__media{
  display:block;overflow:hidden;border-radius:var(--r-leaf);background:var(--skeleton);
  aspect-ratio:161/412;max-height:60vh;margin-inline:auto;width:100%;
}
.pane__media img{width:100%;height:100%;object-fit:cover;scale:1.05}
/* The column rules run from under the bar to the foot of the hero. */
.pane::before,.pane:last-child::after{
  content:"";position:absolute;top:calc(var(--bar-h) * -1);bottom:0;width:1px;
  background:var(--line);transform-origin:top;
  transition:background var(--d-hover) var(--ease-out);
}
.pane::before{left:0}
.pane:last-child::after{right:0}
.pane__title{display:block;margin-top:var(--s-4);font-size:var(--t-title);line-height:var(--lh-title)}
@media (min-width:1024px){
  .pane__title{position:absolute;opacity:0;pointer-events:none;margin:0}
}

/* Hover marquee: the title runs across the whole arch band, pointer only. */
/* Full-bleed and behind the panees: the word passes across the whole stage and is never read
   over a photograph, so its contrast is the stage's contrast whatever the images are. */
.hero__marquee{
  position:absolute;left:50%;top:50%;translate:-50% -50%;width:100vw;
  display:none;overflow:hidden;pointer-events:none;user-select:none;
  z-index:0;opacity:0;transition:opacity var(--d-sheet) var(--ease-out);
}
.pane{z-index:1}
/* The monogram steps back while the word runs, instead of colliding with it. */
.hero__wordmark{transition:opacity var(--d-hover) var(--ease-out)}
.hero:has(.hero__panes[data-hover]) .hero__wordmark{opacity:0}
@media (min-width:1024px) and (hover:hover) and (pointer:fine){ .hero__marquee{display:block} }
.hero__marquee[data-on]{opacity:1}
.hero__marquee-track{
  display:flex;gap:2rem;white-space:nowrap;
  font-size:var(--t-display-l);line-height:var(--lh-display-l);font-weight:300;
  animation:marquee 9s linear infinite;
}
@media (prefers-reduced-motion:reduce){ .hero__marquee{display:none} }
@media (hover:hover) and (pointer:fine){
  .hero__panes[data-hover] .pane:not([data-on])::before{background:var(--line)}
  .pane[data-on]::before,.pane[data-on]:last-child::after{background:var(--accent)}
}

.hero__tagline{
  grid-column:1/-1;grid-row:3;align-self:end;
  max-width:18ch;margin-top:var(--s-8);
}
@media (min-width:1024px){
  .hero__tagline{grid-column:1/span 6;grid-row:1;padding-bottom:1.75rem;margin-top:0;align-self:end}
}

/* Mobile: the three arches become a snap scroller, full bleed. */
@media (max-width:1023px){
  .hero__panes{
    grid-template-columns:none;grid-auto-flow:column;
    /* The track has to honour the same floor as .pane below, or the pane is wider than the
       track it sits in and the arches overlap each other. 33% of a 360px screen is 119px
       against a 140px pane, which is exactly where they started colliding. */
    grid-auto-columns:max(8.75rem,33%);
    overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;
    /* without this the snap pulls the first arch onto the bleed edge, losing its gutter */
    scroll-padding-inline:var(--gutter);
    width:calc(100% + 2 * var(--gutter));margin-inline:calc(var(--gutter) * -1);
    padding-inline:var(--gutter);column-gap:var(--gutter);
  }
  .hero__panes::-webkit-scrollbar{display:none}
  .pane{scroll-snap-align:start;min-width:8.75rem;padding-inline:0}
  .pane__media{aspect-ratio:133/86;max-height:none}
  .pane::before,.pane:last-child::after{top:0}
  @supports (animation-timeline:view()){
    .pane{animation:fade-in .01s both;animation-timeline:view(inline)}
  }
}
@keyframes fade-in{ from{opacity:1} to{opacity:1} }

/* ============================================================== FEED ====== */
.feed{margin-bottom:var(--s-16)}
@media (min-width:1024px){ .feed{margin-bottom:var(--s-35)} }
.feed__list{grid-column:1/-1;display:grid;row-gap:var(--s-12)}
@media (min-width:1024px){ .feed__list{row-gap:var(--s-31)} }

/* ================================================= SPECIALISATION INDEX === */
.spec__list{grid-column:1/-1;border-top:1px solid var(--line)}
.spec__row{
  position:relative;display:grid;grid-template-columns:2ch 1fr auto;
  align-items:center;column-gap:var(--s-4);
  padding-block:var(--s-4);border-bottom:1px solid var(--line);
  transition:border-color var(--d-hover) var(--ease-out);
}
@media (min-width:1024px){ .spec__row{padding-block:var(--s-6)} }
/* Scoped to `a` on purpose: the accent hairline is a link affordance. Both spec lists render as
   plain <li> now (landing expertise, practice studios), so this is inert until a row is a link
   again - which is the point. A non-link that lights up on hover promises a click (R-I10). */
a.spec__row:hover,a.spec__row:focus-visible{border-bottom-color:var(--accent)}
.spec__i{color:var(--muted);font-size:var(--t-tag);font-weight:500;font-variant-numeric:tabular-nums}
.spec__name{display:flex;align-items:center;font-size:var(--t-display-m);line-height:var(--lh-display-m)}
.spec__n{font-size:var(--t-label);font-weight:500;font-variant-numeric:tabular-nums;color:var(--muted)}
.spec__thumb{width:4rem;aspect-ratio:1;border-radius:var(--r-media);object-fit:cover;margin-right:.75rem}
@media (min-width:1024px){ .spec__thumb{display:none} }

/* ============================================================= INTRO ====== */
.intro{padding-block:var(--s-6) var(--s-16)}
@media (min-width:1024px){ .intro{padding-block:var(--s-6) var(--s-23)} }
.intro__media{grid-column:1/-1;order:2;margin-top:var(--s-8);overflow:hidden;border-radius:var(--r-panel)}
.intro__media img{width:100%;aspect-ratio:1008/1466;object-fit:cover}
@media (min-width:1024px){
  .intro__media{grid-column:2/span 9;grid-row:1/4;order:0;margin-top:40.5%}
  @supports (animation-timeline:view()){
    .intro__media img{animation:para linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
  }
}
@keyframes para{ from{translate:0 -6%} to{translate:0 6%} }
.intro__text{grid-column:1/-1}
.intro__figs{grid-column:1/-1;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,7rem),1fr));
  column-gap:var(--s-8);row-gap:var(--s-6);margin-top:var(--s-10)}
.intro__figs > *{min-width:0}
.intro__cta{grid-column:1/-1;margin-top:var(--s-8);justify-self:start}
@media (min-width:1024px){
  .intro__text{grid-column:12/span 12}
  .intro__figs{grid-column:12/span 12}
  .intro__cta{grid-column:12/span 12}
}
.fig__n{display:block;color:var(--accent);font-variant-numeric:tabular-nums;white-space:nowrap}
.fig__l{display:block;color:var(--muted);font-size:var(--t-body-s);margin-top:.25rem}

/* ====================================================== CONTACT STRIP ===== */
.strip{padding-block:var(--s-12);row-gap:var(--s-6);align-items:center;
  --bleed-fill:var(--accent);color:var(--accent-ink)}
.strip .btn--filled .btn__box{background:var(--accent-ink);color:var(--accent)}
.strip .btn--filled .btn__fill{background:var(--accent)}
@media (hover:hover) and (pointer:fine){
  .strip .btn--filled:hover .btn__box{color:var(--accent-ink)}
}
@media (min-width:1024px){ .strip{padding-block:var(--s-20)} }
.strip__text{grid-column:1/-1}
.strip__cta{grid-column:1/-1;justify-self:start}
@media (min-width:1024px){
  .strip__text{grid-column:1/span 14}
  .strip__cta{grid-column:19/-1;justify-self:end}
}

/* ============================================================ FOOTER ====== */
.band{position:relative;overflow:hidden;aspect-ratio:375/271;background:var(--skeleton)}
@media (min-width:1024px){ .band{aspect-ratio:1440/398} }
.band img{width:100%;height:130%;object-fit:cover;position:absolute;inset:0}
@supports (animation-timeline:view()){
  .band img{animation:curtain linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
}
@keyframes curtain{ from{translate:0 -23%} to{translate:0 0} }
@media (prefers-reduced-motion:reduce){
  .band img{height:100%;animation:none;translate:0}
}

.foot__top{padding-block:var(--s-8);row-gap:var(--s-8);justify-items:center;text-align:center}
.foot__social,.foot__lang,.foot__cta{grid-column:1/-1}
.foot__social{display:flex;gap:1.25rem;flex-wrap:wrap;justify-content:center}
/* F28/R-A05: the social links are a list, not prose, so the WCAG 2.5.8 inline exception does not
   cover them; they measured 26px tall. Padding, not font-size, and only where the pointer is a
   finger, so the desktop footer rhythm is untouched. */
@media (pointer:coarse){
  .foot__social a{display:inline-flex;align-items:center;min-height:2.75rem}
}
@media (min-width:1024px){
  .foot__top{padding-block:var(--s-12);justify-items:stretch;text-align:left}
  .foot__social{grid-column:2/span 12;justify-content:flex-start}
  .foot__lang{grid-column:14/span 5}
  .foot__cta{grid-column:19/span 5;justify-self:end}
}

.foot__offices{margin-top:var(--s-8);row-gap:var(--s-10)}
@media (min-width:1024px){ .foot__offices{margin-top:var(--s-31)} }
.office{grid-column:1/span 6}
.office:last-child{grid-column:1/-1}
@media (min-width:1024px){
  .office{grid-column:auto/span 5}
  .office:nth-child(1){grid-column:2/span 5}
  .office:nth-child(2){grid-column:9/span 5}
  .office:nth-child(3){grid-column:16/span 5}
}
.office__addr{margin-top:.5rem;font-style:normal;color:var(--muted)}
/* 44px tap target without opening up the address block: the box grows, the rhythm does not. */
.office__addr a{display:inline-flex;align-items:center;min-height:2.75rem;margin-block:-.6rem}
.office__cta{margin-top:.75rem}

/* Divergence §4.8: the terminal wordmark is drawn, not filled. */
.foot__mark{grid-column:1/-1;margin-top:var(--s-12)}
@media (min-width:1024px){ .foot__mark{grid-column:2/-2;margin-top:var(--s-20)} }
.foot__mark svg{width:100%;height:auto;fill:none;stroke:var(--line-strong);stroke-width:6;
  vector-effect:non-scaling-stroke}

.foot__bottom{margin-top:2.125rem;padding-block:.625rem 2.125rem;row-gap:var(--s-4);align-items:center}
.foot__legal{grid-column:1/-1;display:flex;gap:1.25rem;flex-wrap:wrap}
.foot__copy{grid-column:1/-1;color:var(--muted)}
.foot__up{grid-column:1/-1;justify-self:start}
/* Hidden visually below 1024, never removed: display:none would strip the link's name. */
.foot__up .btn__label{position:absolute;width:1px;height:1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap}
@media (min-width:1024px){
  .foot__legal{grid-column:2/span 9} .foot__copy{grid-column:11/span 4}
  .foot__up{grid-column:20/span 4;justify-self:end}
  .foot__up .btn__label{position:relative;width:auto;height:auto;clip-path:none}
}
.underline-hover{padding-bottom:.1rem}
@media (hover:hover) and (pointer:fine){
  .underline-hover:hover{background-image:linear-gradient(var(--accent),var(--accent));
    background-size:100% 1px;background-repeat:no-repeat;background-position:0 100%;color:var(--accent)}
}

/* =========================================================== GALLERY ====== */
.gal{grid-column:1/-1;display:grid;grid-template-columns:repeat(var(--cols),minmax(0,1fr));
  column-gap:calc(var(--gutter) / 2);row-gap:var(--s-12)}
@media (min-width:1024px){ .gal{row-gap:var(--s-31)} }
.gal__item{grid-column:1/-1}
@media (min-width:768px){
  .gal__item{grid-column:auto/span 4}
  .gal__item--tall{grid-column:auto/span 6}
}
@media (min-width:1024px){
  .gal__item{grid-column:auto/span 6}
  .gal__item--tall{grid-column:auto/span 12}
  .gal__item--tall + .gal__item--tall{margin-top:23.8%}
}
.gal__item[hidden]{display:none}
/* One line, scrolled if it does not fit. Wrapping made the row's height depend on label widths,
   so the webfont swap re-wrapped it and pushed the gallery down: CLS 0.175 on /work/. */
.filters{
  grid-column:1/-1;display:flex;gap:.5rem;flex-wrap:nowrap;
  overflow-x:auto;scrollbar-width:none;scroll-padding-inline:var(--gutter);
  min-height:2.75rem;margin-bottom:var(--s-8);
}
.filters::-webkit-scrollbar{display:none}
.filters .chip{flex:none}

/* ============================================================== PROSE ===== */
.prose{grid-column:1/-1;max-width:65ch}
@media (min-width:1024px){ .prose{grid-column:6/span 14} }
.prose h2{font-size:var(--t-display-s);line-height:var(--lh-display-s);margin-top:var(--s-10)}
.prose h3{font-size:var(--t-title);font-weight:500;margin-top:var(--s-6)}
.prose p,.prose li{margin-top:var(--s-4)}
.prose ul{list-style:disc;padding-left:1.25rem}
.prose a{background-image:linear-gradient(var(--line-strong),var(--line-strong));
  background-size:100% 1px;background-repeat:no-repeat;background-position:0 100%}
.nav-scroll__list{display:flex;gap:.5rem}
.note{grid-column:1/-1;margin-top:var(--s-6);max-width:65ch}
@media (min-width:1024px){ .note{grid-column:1/span 10} }

/* Utility classes replacing inline style attributes, so the CSP needs no unsafe-inline at all. */
.sentinel{position:absolute;top:0;width:1px;height:1px}
.chip-row{display:flex;gap:.5rem;flex-wrap:wrap;margin-top:var(--s-6)}
.form-status{margin-bottom:var(--s-4)}
.form-status[data-state="error"]{color:var(--ink);font-weight:500}
.offices--page{margin-top:var(--s-16)}
.prose--spaced{margin-top:var(--s-12)}
.gal__empty{grid-column:1/-1;max-width:45ch;margin-top:var(--s-8);color:var(--muted)}
.studio__list .studio__body{padding-block:0 var(--s-6);border-bottom:1px solid var(--line)}
@media (min-width:1024px){
  .studio__list .spec__row{border-bottom:0;padding-bottom:var(--s-2)}
  .studio__list .studio__body{padding-left:calc(2ch + var(--s-4))}
}
/* ---- motion.css ---- */
/* zwornik — motion. Initial states are gated on `.js` so a no-JS page renders finished,
   and on `no-preference` so reduced motion never has anything to undo. */

@media (prefers-reduced-motion:no-preference){
  /* Hero entry: establishes the section map before anything can be clicked. */
  .js .hero__wordmark svg{clip-path:inset(100% 0 0 0)}
  .js .hero__tagline{opacity:0}
  .js .pane{opacity:0}
  .js .pane{--rule-scale:0}
  .js body[data-hero] .bar{translate:0 -100%}
}
.pane::before,.pane:last-child::after{scale:1 var(--rule-scale,1)}

/* Resting composition: the three arch tops form a diagonal. In CSS, not in the timeline, so it
   survives no-JS and reduced motion; GSAP animates yPercent on top of it and lands on 0. */
.pane:nth-child(1) .pane__media{translate:0 -3%}
.pane:nth-child(2) .pane__media{translate:0 -15%}
.pane:nth-child(3) .pane__media{translate:0 13%}
@media (max-width:1023px){ .pane .pane__media{translate:0 0} }

/* Scroll reveals: zero-JS where the browser has view timelines, IntersectionObserver elsewhere. */
@media (prefers-reduced-motion:no-preference){
  @supports (animation-timeline:view()){
    .reveal{animation:reveal-up linear both;animation-timeline:view();
      animation-range:entry 0% entry 45%}
    .reveal .card__media,.reveal .intro__figs div{animation:reveal-fade linear both;
      animation-timeline:view();animation-range:entry 0% entry 35%}
  }
  @supports not (animation-timeline:view()){
    .js .reveal{translate:0 1.25rem;
      transition:translate .6s var(--ease-out-quart);transition-delay:var(--rd,0ms)}
    .js .reveal.is-in{translate:0 0}
    .js .reveal .card__media{opacity:0;transition:opacity .6s var(--ease-out-quart)}
    .js .reveal.is-in .card__media{opacity:1}
  }
}
@keyframes reveal-up{ from{translate:0 1.25rem} to{translate:0 0} }
@keyframes reveal-fade{ from{opacity:0} to{opacity:1} }
