:root{
  /* A committed light-grey ground, the way the old site was fixed grey.
     Single look by design: no dark inversion, so the page reads the same
     for every visitor regardless of their system theme. */
  --paper:#e3e3e1;
  --ink:#2f2f2c;
  --reverse:#ffffff;
  --meta:#6e6e68;
  --hair:#2f2f2c;
  --well:#d2d2d0;
  --field:#f2f2f0;
  --flag:#0b3bdb;
  --dot-id:#e2650f;
  --dot-other:#6e6e68;
  --flag-text:#ffffff;
  --mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --bar-h:26px;
  --row-h:30px;
  --irow-h:56px;
  --ithumb-w:210px;
  --pad:10px;
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--mono);
  font-size:13px;
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
}
button,input,textarea,select{font:inherit;color:inherit}
a{color:inherit;text-decoration:none}
::selection{background:var(--ink);color:var(--reverse)}
:focus-visible{outline:2px solid var(--flag);outline-offset:1px}

/* ---------- masthead ---------- */
.mast{position:sticky;top:0;z-index:60;background:var(--paper)}
.mrow{
  display:flex;align-items:center;justify-content:space-between;
  height:var(--row-h);padding:0 var(--pad);
  border-bottom:1px solid var(--hair);
}
.mrow--top{font-size:13.5px;letter-spacing:-.01em}
.mrow--nav{font-size:11.5px;text-transform:uppercase;letter-spacing:.04em}
.navgroup{display:flex;align-items:center;gap:20px}
@media (max-width:420px){.navgroup{gap:12px}.mrow--nav{font-size:10px}
  .mrow--top{font-size:12px}}
.brand{font-weight:600;letter-spacing:.22em;
  background:none;border:0;padding:0;cursor:pointer;text-align:left}
.mrow--nav button{background:none;border:0;padding:0;cursor:pointer;
  text-transform:uppercase;letter-spacing:.04em;font-family:var(--mono)}
.mrow--nav button[aria-current="true"]{text-decoration:underline;text-underline-offset:3px}
.nav-enter{font-weight:600}
.ig{display:block;width:17px;height:17px}
.ig svg{display:block;width:100%;height:100%;fill:none;stroke:var(--ink);stroke-width:1.4}

/* ---------- bars ---------- */
.bars{display:flex;flex-direction:column;gap:1px;margin-top:1px}
.bar{
  display:flex;align-items:center;justify-content:center;position:relative;
  min-height:var(--bar-h);background:var(--ink);color:var(--reverse);
  font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:.05em;
  padding:4px 36px;text-align:center;
  border:0;width:100%;cursor:default;font-family:inherit;
}
button.bar{cursor:pointer}
button.bar:hover .bar__t{text-decoration:underline;text-underline-offset:3px}
/* Inside a project the bars take the page's own grey instead of white:
   these three sit against the work, where pure white glares. The
   division and About bars stay white. */
.bar--project{color:var(--paper)}
.bar--off{background:var(--well);color:var(--meta)}
.bar--on{background:var(--paper);color:var(--ink);box-shadow:inset 0 0 0 1px var(--hair)}
.bar--flag{background:var(--flag);color:var(--flag-text);cursor:pointer}
.bar__l,.bar__r{position:absolute;top:0;bottom:0;display:flex;align-items:center;
  padding:0 var(--pad);background:none;border:0;color:inherit;cursor:pointer}
.bar__l{left:0}
.bar__r{right:0}
.bar__meta{font-size:10px;letter-spacing:.02em;font-variant-numeric:tabular-nums}

/* ---------- type specimen ---------- */
@font-face{
  font-family:"GD New Spirit";
  src:url("fonts/GD_NewSpirit-Regular.otf?v=1793964935") format("opentype");
  font-weight:400;font-style:normal;font-display:swap;
}
@font-face{
  font-family:"Doordash Soccer";
  src:url("fonts/DoordashSoccer-Regular.otf?v=1793964935") format("opentype");
  font-weight:400;font-style:normal;font-display:swap;
}
/* Ranged with the project index above it (1056px), so the rules, the
   tester and the gallery all stop on the same line the index does. */
/* Indented by --pad so the label, the controls and the rules all start
   on the same line as DESIGN / TYPOGRAPHY / ABOUT in the menu above,
   while the right edge still stops where the project index stops. */
.spec{max-width:calc(1056px + var(--pad));margin:8px 0 0;
  padding:0 var(--pad) 26px}
/* A second specimen opens a little below the one before it. */
.spec + .spec,.spec-gal + .spec{margin-top:30px}
/* The typeface named above its own controls, in the site's mono so it
   reads as a label rather than as part of the specimen. */
.spec__name{font-size:11px;font-weight:500;text-transform:uppercase;
  letter-spacing:.1em;color:var(--meta);padding:14px 0 0}
.spec__bar{display:flex;flex-wrap:wrap;gap:0 28px;align-items:center;
  padding:10px 0 18px;border-bottom:1px solid var(--hair)}
.spec__ctrl{display:flex;align-items:center;gap:8px}
.spec__lab{font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:var(--meta)}
.spec__val{font-size:10px;color:var(--meta);font-variant-numeric:tabular-nums;min-width:3.5em}
.spec__ctrl input[type=range]{
  -webkit-appearance:none;appearance:none;width:120px;height:1px;
  background:var(--hair);outline:0;cursor:pointer}
.spec__ctrl input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none;width:9px;height:9px;border-radius:50%;
  background:var(--ink);cursor:pointer}
.spec__ctrl input[type=range]::-moz-range-thumb{
  width:9px;height:9px;border:0;border-radius:50%;background:var(--ink);cursor:pointer}
/* The specimen itself, set in the typeface being shown. */
.spec__test{
  font-family:var(--mono);          /* the face is set per specimen */
  color:var(--ink);outline:0;
  /* The gap above the specimen is measured to the cap tops, the gap
     below to the baseline, and the two differ by a tenth of the type
     size: this face's caps stop 0.092em under the line box top and
     its baseline sits 0.008em below the bottom. Adding that tenth to
     the lower padding makes the two read equal, and because it is in
     em it stays equal as the size slider moves. */
  padding:28px 0 calc(28px + var(--spec-k, .1) * 1em);
  word-break:break-word;caret-color:var(--dot-id);
  /* Closed off below as well, so the specimen sits between two rules
     rather than trailing away into the page. */
  border-bottom:1px solid var(--hair);
}
/* A gallery under the tester that plays itself: the plates cross-fade in
   one frame, so the section keeps the height of a single image. */
/* The gap below the tester's rule is the .spec padding above and nothing
   here, so it is one number to move rather than two that must agree. */
.spec-gal{max-width:calc(1056px + var(--pad));padding:0 var(--pad)}
.spec-gal__frame{position:relative;width:100%;aspect-ratio:16/9;
  background:var(--well);overflow:hidden}
.spec-gal__frame img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;opacity:0;transition:opacity .55s ease}
.spec-gal__frame img.on{opacity:1}
/* Reduced motion: nothing fades, so the plates stack down the page
   instead of five of them sitting hidden behind the first. */
.spec-gal--still .spec-gal__frame{position:static;aspect-ratio:auto;
  display:grid;gap:14px;background:none;overflow:visible}
.spec-gal--still .spec-gal__frame img{position:static;width:100%;height:auto;
  opacity:1;transition:none}

@media (max-width:640px){
  .spec{padding-bottom:20px}
  /* The rules were set for 112px type; at 65px the same padding leaves
     the specimen floating. Tightened to keep the desktop proportion. */
  .spec__test{padding:16px 0 calc(16px + var(--spec-k, .1) * 1em)}
  /* Both controls on one row: they share the width between them and the
     sliders give way, rather than the second wrapping under the first. */
  .spec__bar{flex-wrap:nowrap;gap:0 14px}
  .spec__ctrl{flex:1 1 0;min-width:0}
  .spec__lab,.spec__val{flex:0 0 auto}
  .spec__ctrl input[type=range]{width:auto;flex:1 1 auto;min-width:34px}
  /* Three controls do not fit a phone, and leading is the one a reader
     least needs on a single line. */
  .spec__ctrl--leading{display:none}
}

/* ---------- typography flipbook ---------- */
/* The specimens cycle in a single frame instead of lying flat in a grid —
   the loop a GIF would have given, built from the images the page already
   carries. Left-aligned like everything else, so the right margin holds. */
.flip{margin:8px 0 0;padding:0 0 40px;
  display:flex;flex-direction:column;align-items:center}
.flip__frame{
  position:relative;width:min(46vw,480px);aspect-ratio:3/4;
  background:var(--well);overflow:hidden;
}
.flip__frame img{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;opacity:0;
}
.flip__frame img.on{opacity:1}
/* Set like the empty-division note it replaces, and ranged with the frame. */
.flip__soon{
  margin:0;padding:22px 0 0;
  font-size:13px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink);
  text-align:center;
}
@media (max-width:900px){
  .flip__frame{width:min(76vw,480px)}
}

/* ---------- index ---------- */
/* The work reads as a list rather than a field of tiles: one line per
   project, the cover reduced to a strip that keeps the row's rhythm.
   Capped and left-aligned like the grid it replaces, so the page keeps
   its open right-hand margin. */
.index{max-width:1056px;margin:8px 0 0;padding:0 0 40px;
  border-top:1px solid var(--hair)}
.irow{
  display:grid;grid-template-columns:var(--ithumb-w) minmax(0,1fr) auto;
  align-items:center;gap:0 14px;
  width:100%;min-height:var(--irow-h);
  background:none;border:0;border-bottom:1px solid var(--hair);
  padding:0 var(--pad) 0 0;margin:0;
  font:inherit;color:inherit;text-align:left;cursor:pointer;
}
.irow__thumb{position:relative;display:block;overflow:hidden;
  width:var(--ithumb-w);height:var(--irow-h);background:var(--well)}
/* The box carries the grid's 4:3 geometry so a framed cover crops exactly
   as it does there; centring the box is what turns the crop into a band. */
.irow__box{position:absolute;left:0;top:50%;transform:translateY(-50%);
  display:block;width:100%;aspect-ratio:4/3}
.irow__box img,.irow__box svg{display:block;width:100%;height:100%;
  object-fit:cover;object-position:left center}
.irow__box img.tile__framed{position:absolute;top:0;left:0;
  height:auto;max-width:none;object-fit:fill;object-position:0 0;transform:none}
.irow__t{font-size:12px;font-weight:500;text-transform:uppercase;letter-spacing:.05em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.irow__m{font-size:11px;letter-spacing:.02em;color:var(--meta);
  text-transform:uppercase;white-space:nowrap}
/* Sits in the row's last column, so it ends the line and rides the title's
   centre line without being placed by hand. */
.irow__dot{display:block;width:14px;height:14px;border-radius:50%;
  background:var(--dot-other);flex:none}
.irow__dot--id{background:var(--dot-id)}
/* Inverting the whole line, the way the bars are inverted, rather than
   tinting it: the index is meant to feel switched, not shaded. */
.irow:hover,.irow:focus-visible{background:var(--ink);color:var(--reverse);outline:0}
.irow:hover .irow__m,.irow:focus-visible .irow__m{color:var(--reverse)}
@media (max-width:640px){
  /* On a phone the row is all it can afford: thumbnail and title. The dot
     and the category both go, and the grid loses the column that held them
     rather than leaving a gap at the end of every line. */
  .irow{grid-template-columns:var(--ithumb-w) minmax(0,1fr);gap:0 10px}
  .irow__m,.irow__dot{display:none}
}

/* ---------- grid ---------- */
/* Three across: with fifteen projects that lands on exactly five rows.
   Capped and left-aligned rather than stretched, so the block sits against
   the left edge and the page keeps its open right-hand margin. */
.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  max-width:1056px;justify-items:stretch;justify-content:start;
  gap:0;margin:8px 0 0;padding:0 0 40px}
@media (max-width:640px){.grid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:420px){.grid{grid-template-columns:1fr}}
.tile{position:relative;aspect-ratio:4/3;overflow:hidden;background:var(--well);
  border:0;padding:0;cursor:pointer;display:block;color:inherit}
.tile img,.tile svg{display:block;width:100%;height:100%;
  object-fit:cover;object-position:left center}
/* The old site framed a tile by oversizing the image inside a 4:3 box and
   pulling it with negative margins. Reproduced by taking the image out of
   flow and letting its inline width + margins place it, so it cannot
   disturb the grid and object-fit never intervenes. */
.tile img.tile__framed,.landing__frame img.tile__framed{
  position:absolute;top:0;left:0;
  height:auto;max-width:none;
  object-fit:fill;object-position:0 0;transform:none;
}
.tile__cap{
  position:absolute;left:0;right:0;bottom:0;background:var(--ink);color:var(--reverse);
  font-size:9px;line-height:1.35;text-transform:uppercase;letter-spacing:.02em;
  padding:5px 6px;opacity:0;transform:translateY(100%);
  transition:opacity .12s linear,transform .12s ease-out;
  text-align:left;
}
.tile:hover .tile__cap,.tile:focus-visible .tile__cap{opacity:1;transform:translateY(0)}
@media (hover:none){.tile__cap{opacity:1;transform:translateY(0);
  background:color-mix(in srgb,var(--ink) 82%,transparent)}}
@media (prefers-reduced-motion:reduce){.tile__cap{transition:none}}
.tile__cat{color:var(--meta);display:block}

/* ---------- landing montage ---------- */
.landing{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:0;cursor:pointer;
  min-height:calc(100vh - 2*var(--row-h) - 2px);
  padding:24px var(--pad) 40px;
}
.landing__frame{
  position:relative;width:min(31vw,440px);aspect-ratio:4/3;
  background:var(--well);overflow:hidden;
}
.landing__frame img{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:left center;
  opacity:0;
}
.landing__frame img.on{opacity:1}
@media (max-width:900px){
  .landing__frame{width:min(72vw,520px)}
}
@media (max-width:640px){
  /* No telemóvel a montagem fica a meio de um ecrã alto, o que a deixa
     baixa de mais. Mais espaço por baixo levanta o ponto de equilíbrio
     sem a encostar ao topo. */
  .landing{padding-bottom:22vh}
}
@media (prefers-reduced-motion:reduce){
  .landing__frame img{transition:none}
}

/* ---------- project plates ---------- */
/* Plates sit in a centred column rather than full bleed.
   One number controls how large they run. */
.plates{
  --plate-w:min(52vw,840px);
  display:flex;flex-direction:column;align-items:center;
  gap:14px;padding:14px 0 70px;
}
.plate{width:var(--plate-w);max-width:100%;background:var(--well);position:relative}
.plate img{display:block;width:100%;height:auto}
.plate-row{display:flex;gap:14px;width:var(--plate-w);max-width:100%;align-items:flex-start}
.plate-row>.plate{width:auto;flex:1 1 0;min-width:0}
@media (max-width:560px){.plate-row{gap:10px}}
.plate--video{background:#000}
.plate--video iframe,
.plate--video video{display:block;width:100%;height:100%;border:0}
/* A film we host fills its plate the way a still does. */
.plate--video video{object-fit:cover}
@media (max-width:900px){.plates{--plate-w:74vw}}
@media (max-width:560px){.plates{--plate-w:calc(100vw - 2*var(--pad));gap:10px}}
.plate__n{position:absolute;left:var(--pad);top:8px;font-size:10px;
  color:var(--reverse);mix-blend-mode:difference;font-variant-numeric:tabular-nums}
.plate__cap{width:var(--plate-w);max-width:100%;font-size:11px;color:var(--meta);
  padding:0;background:var(--paper);margin-top:-6px}

/* ---------- prose / about ---------- */
.sheet{padding:22px var(--pad) 70px;max-width:none}
/* Words left, portrait right. The text column keeps its own measure; the
   portrait takes what is left, to a sensible cap. */
.sheet--about{
  display:grid;grid-template-columns:minmax(0,46ch) minmax(0,290px);
  gap:0 clamp(24px,4vw,64px);align-items:start;
}
/* The bio sets a touch smaller than body copy elsewhere, so the words
   sit under the portrait's weight rather than competing with it. */
.sheet--about .lede{font-size:14px;line-height:1.5;margin-bottom:1.2em}
.sheet--about .col p{font-size:12px}
.sheet--about .info__row{font-size:11px;padding:5px 0}
.sheet--about .info__k{font-size:9.5px}
.about__figure{margin:0;min-width:0}
.about__portrait{display:block;width:100%;height:auto}
@media (max-width:900px){
  .sheet--about{grid-template-columns:minmax(0,46ch);gap:28px 0}
  .about__figure{max-width:290px}
}
.col{max-width:54ch}
.col p{margin:0 0 1em}
.col p:last-child{margin-bottom:0}
.lede{font-size:16px;line-height:1.45;text-wrap:balance;margin:0 0 1.3em;font-weight:500;
  letter-spacing:-.01em}
.info{margin-top:30px;border-top:1px solid var(--hair);max-width:none}
.info__row{display:flex;gap:16px;padding:6px 0;border-bottom:1px solid var(--hair);
  font-size:12px;align-items:baseline}
.info__k{flex:0 0 38%;text-transform:uppercase;letter-spacing:.04em;color:var(--meta);font-size:10px}
.info__v{flex:1 1 auto;word-break:break-word}

/* ---------- awards tally ---------- */
.awards{padding:16px var(--pad) 70px;columns:232px;column-gap:26px}
.awgroup{break-inside:avoid;margin:0 0 16px}
.awgroup__h{font-size:10px;text-transform:uppercase;letter-spacing:.06em;font-weight:600;
  padding-bottom:4px;border-bottom:1px solid var(--hair);margin:0 0 1px}
.awrow{display:flex;justify-content:space-between;align-items:baseline;gap:10px;
  font-size:11.5px;padding:3px 0;border-bottom:1px solid var(--well)}
.awrow__n{min-width:0;overflow-wrap:anywhere}
.awrow__c{flex:0 0 auto;color:var(--meta);font-variant-numeric:tabular-nums}
.awgroup--solo{border-top:1px solid var(--hair);padding-top:5px}

/* ---------- edit layer ---------- */
.edit{padding:0 0 80px}
.sect{border-bottom:1px solid var(--hair);padding:14px var(--pad) 18px}
.sect__h{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--meta);
  margin:0 0 10px;font-weight:500}
.f{display:flex;flex-direction:column;gap:4px;margin-bottom:10px;max-width:54ch}
.f label{font-size:9.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--meta)}
.f input,.f textarea,.f select{
  background:var(--field);border:1px solid var(--hair);border-radius:0;
  padding:6px 7px;font-size:12.5px;width:100%;font-family:var(--mono);
}
.f textarea{min-height:104px;resize:vertical;line-height:1.5}
.f--row{flex-direction:row;gap:8px;max-width:54ch}
.f--row>*{flex:1 1 0;min-width:0}
.btn{
  background:var(--field);color:var(--ink);border:1px solid var(--hair);
  padding:5px 11px;font-size:10px;text-transform:uppercase;letter-spacing:.05em;
  cursor:pointer;border-radius:0;font-family:var(--mono);
}
.btn:hover{background:var(--ink);color:var(--reverse)}
.btn--solid{background:var(--flag);color:var(--flag-text);border-color:var(--flag)}
.btn--solid:hover{background:var(--ink);color:var(--reverse);border-color:var(--hair)}
.btn--danger:hover{background:#c02414;color:#fff;border-color:#c02414}
.btn:disabled{opacity:.4;cursor:not-allowed}
.btn:disabled:hover{background:var(--paper);color:var(--ink)}
.btnrow{display:flex;flex-wrap:wrap;gap:6px;align-items:center}

.drop{border:1px dashed var(--hair);padding:20px var(--pad);text-align:center;
  font-size:10.5px;text-transform:uppercase;letter-spacing:.04em;color:var(--meta);
  cursor:pointer;background:var(--paper)}
.drop[data-over="true"]{border-color:var(--flag);border-style:solid;color:var(--flag)}

.strip{display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:6px;
  margin-top:10px}
.shot{border:1px solid var(--hair);background:var(--well);position:relative}
.shot img{display:block;width:100%;aspect-ratio:5/7;object-fit:cover}
.shot__bar{display:flex;border-top:1px solid var(--hair)}
.shot__bar button{flex:1 1 0;background:var(--paper);border:0;border-left:1px solid var(--hair);
  padding:3px 0;font-size:10px;cursor:pointer;line-height:1.4;font-family:var(--mono)}
.shot__bar button:first-child{border-left:0}
.shot__bar button:hover{background:var(--ink);color:var(--reverse)}
.shot__flag{position:absolute;top:0;left:0;background:var(--flag);color:var(--flag-text);
  font-size:8.5px;letter-spacing:.05em;padding:2px 5px;text-transform:uppercase}

.list{border-top:1px solid var(--hair)}
.item{display:flex;align-items:center;gap:10px;padding:7px var(--pad);
  border-bottom:1px solid var(--hair)}
.item__th{flex:0 0 30px;width:30px;aspect-ratio:5/7;object-fit:cover;background:var(--well)}
.item__b{flex:1 1 auto;min-width:0}
.item__t{font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.item__m{font-size:9.5px;text-transform:uppercase;letter-spacing:.04em;color:var(--meta)}
.item__a{flex:0 0 auto;display:flex;gap:4px}

.note{font-size:11px;color:var(--meta);margin:0 0 10px;max-width:54ch}
.meter{height:3px;background:var(--well);margin-top:5px;max-width:54ch}
.meter>i{display:block;height:100%;background:var(--flag)}
.mono{font-size:11px;font-variant-numeric:tabular-nums;color:var(--meta)}
.chips{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}
.chip{font-size:9.5px;text-transform:uppercase;letter-spacing:.04em;border:1px solid var(--hair);
  padding:2px 6px}

.toast{position:fixed;left:var(--pad);bottom:var(--pad);z-index:300;
  background:var(--ink);color:var(--reverse);font-size:10px;text-transform:uppercase;
  letter-spacing:.05em;padding:6px 10px;opacity:0;pointer-events:none;transition:opacity .18s}
.toast[data-on="true"]{opacity:1}
@media (prefers-reduced-motion:reduce){.toast{transition:none}}
.hide{display:none !important}
.empty{padding:40px var(--pad);color:var(--meta);font-size:11px;text-transform:uppercase;
  letter-spacing:.04em;text-align:center}
/* An empty division: left-aligned with the grid it stands in for, and given
   room so the page does not look broken. */
.empty--soon{
  text-align:left;padding:64px 0 96px;margin:8px 0 0;
  max-width:1056px;font-size:13px;letter-spacing:.06em;color:var(--ink);
}
