/* ============================================================================
   PINHEIRO R&D — main.css

   Restraint is the brief: the attractor is the only rich thing on the page and
   everything around it holds still. Type, hairlines, whitespace. No cards, no
   boxes, no shadows, no gradients.

   Every theme-able value is a :root custom property, because the studio's
   #edit panel lists exactly those — hard-code a colour and it drops out.

   ⚠️ Small type has a hard floor of 4.5:1. Measured on --paper: --ink-faint is
   4.58:1, --ochre 5.03:1, --turquoise 5.77:1. --ink-ghost (2.0:1) is ONLY for
   aria-hidden decoration. Compute the ratio before putting a colour on text.
   ========================================================================= */

:root{
  /* ---- palette, from the swatch supplied 2026-09-07 -----------------------
     --fig-* are FIGURE colours: they are drawn on the canvas and never put on
     text, which is why they are allowed below the 4.5:1 floor. The contrast
     checker exempts the prefix for exactly that reason — do not use one of
     these on type.
     ⚠️ Read off the image, not from hex values — correct these four lines if
     they are a shade out and everything downstream follows.
       C01 41% ink · C02 16% red · C03 15% brown · C04 9% tan
       C05  7% sky · C06  7% brick · C07 4% yellow · C08 0% paper            */
  --fig-ink:     #140B08;
  --fig-red:     #E5230F;
  --fig-brown:   #3A2A19;
  --fig-tan:     #6D4E2A;
  --fig-sky:     #6BD3ED;
  --fig-brick:   #A81D11;
  --fig-yellow:  #F7EC00;
  --fig-paper:   #E7E7EF;

  /* ---- what the page actually uses --------------------------------------
     The swatch's near-white is a cool lavender; used flat it turns the page
     grey, so the paper is lightened from it and the ink is the swatch's C01.
     Every value here is measured: see the contrast note at the top.          */
  --paper:        #F7F7FA;
  --ink:          #140B08;              /* 17.8:1 */
  --ink-soft:     rgba(20,11,8,.60);    /*  4.6:1 */
  --ink-faint:    rgba(20,11,8,.60);
  --ink-ghost:    rgba(20,11,8,.32);    /* decoration only */
  /* The accent that carries links, numbers and the active state. C06 umber
     from the colour graph, 6.37:1 — the only warm tone in the palette that
     clears the 4.5:1 floor for small text. The oranges measure 2.5–3.4:1 and
     are therefore FIGURE colours: marks, bars, ribbons, the canvas. Never type. */
  --accent:       #8A4A20;
  --fig-lit:      #F08000;              /* C01, 2.52:1 — marks, never type    */
  /* One colour per research route. All three share a border with the hub in
     the colour graph, so they are a licensed family — and they separate by
     temperature as well as hue: bright warm, dark warm, cool. */
  --fig-r1:       #F08000;              /* C01 orange                        */
  --fig-r2:       #8A4A20;              /* C06 umber                         */
  --fig-r3:       #7C86AE;              /* C03 periwinkle, deepened to read as a fill */
  --fig-warm:     #C0622A;              /* C04, 3.91:1 — marks, never type    */
  --ochre:        #6D4E2A;
  --turquoise:    #1F6E67;
  --hairline:     rgba(20,11,8,.16);
  --rule:         rgba(20,11,8,.10);

  --font-display: "Newsreader", Georgia, "Times New Roman", serif;
  --font-body:    "IBM Plex Sans", system-ui, -apple-system, sans-serif;
  --font-mono:    "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --fs-h1:    clamp(2.5rem, 5.2vw, 4.4rem);
  --fs-h2:    clamp(1.6rem, 2.9vw, 2.4rem);
  --fs-body:  clamp(.97rem, 1.1vw, 1.04rem);
  --fs-label: 11px;

  --gutter:  clamp(22px, 5.4vw, 96px);
  --maxw:    1360px;
  --band:    clamp(52px, 7.5vh, 104px);
}

*{margin:0;padding:0;box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
@media (prefers-reduced-motion: reduce){ html{scroll-behavior:auto} }
body{
  background:var(--paper);color:var(--ink);
  font-family:var(--font-body);font-size:var(--fs-body);line-height:1.6;
  -webkit-font-smoothing:antialiased;
}

.mono,.eyebrow,.navlink,.wordmark,.cta,.caption,.tag,.field-label{
  font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:.18em;text-transform:uppercase;font-weight:400;
}
.eyebrow{display:block;color:var(--ink-faint)}
h1,h2,h3{font-family:var(--font-display);font-weight:400;font-optical-sizing:auto}
h1{font-size:var(--fs-h1);line-height:1.02;letter-spacing:-.018em}
h2{font-size:var(--fs-h2);line-height:1.12;letter-spacing:-.012em}
h3{font-size:1.12rem;line-height:1.3}
p{max-width:58ch}
a{color:inherit}
a:focus-visible,button:focus-visible,input:focus-visible,textarea:focus-visible,
[tabindex]:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:1px}
.soft{color:var(--ink-soft)}
.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

.cta{
  display:inline-block;color:var(--ink);text-decoration:none;
  border-bottom:1px solid var(--ink);padding-bottom:5px;
  transition:color .18s ease,border-color .18s ease;
}
.cta:hover,.cta:focus-visible{color:var(--accent);border-color:var(--accent)}

/* ---------------------------------------------------------------- reveal
   Content rises as it is reached — the page assembles rather than sitting
   there finished. Small distances only: a big translate is a vestibular
   trigger and reads as a slideshow. Anything that has not been observed yet
   stays visible, so a failed observer can never hide the page. */
.rise{opacity:0;transform:translateY(12px);
      transition:opacity .65s cubic-bezier(.2,.7,.2,1) var(--d,0s),
                 transform .65s cubic-bezier(.2,.7,.2,1) var(--d,0s)}
.rise.is-in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .rise{opacity:1;transform:none;transition:none}
}

/* ---------------------------------------------------------------- header */
.site-header{
  position:fixed;top:0;left:0;right:0;z-index:20;
  display:flex;justify-content:space-between;align-items:baseline;gap:24px;
  padding:24px var(--gutter);
  /* ⚠️ O SEGUNDO STOP TEM DE SER O MESMO PAPEL, A ZERO. Estava escrito
     rgba(251,250,247,0) — o papel de duas paletas atrás. Um stop transparente
     de OUTRA cor não é invisível: o Chrome interpola em premultiplicado e a
     faixa ganha um véu com a cor errada. Com `transparent` o navegador usa
     rgba(0,0,0,0) e o degradê escurece pelo meio. Daí a função. */
  background:linear-gradient(var(--paper) 62%, rgb(from var(--paper) r g b / 0));
  transition:background .3s ease;
}
.wordmark{font-weight:500;text-decoration:none;letter-spacing:.2em;white-space:nowrap}
.site-nav{display:flex;gap:clamp(16px,2.4vw,34px);align-items:baseline}
.navlink{color:var(--ink-soft);text-decoration:none;transition:color .18s ease;white-space:nowrap}
.navlink:hover,.navlink[aria-current="page"]{color:var(--ink)}
.navlink[aria-current="page"]::before{
  content:"";display:inline-block;width:4px;height:4px;margin-right:7px;
  vertical-align:middle;background:var(--accent);
}
.nav-toggle{display:none;background:none;border:none;cursor:pointer;color:var(--ink-soft)}

/* ---------------------------------------------------------------- hero */
.hero{position:relative;min-height:100svh;display:flex;align-items:center;
      padding:clamp(96px,14vh,140px) var(--gutter) clamp(56px,9vh,96px)}
/* One fixed plate behind the whole document; every section scrolls over it.
   Sections must stay transparent or they hide it — do not give .band a
   background. */
/* ⚠️ THE BACKGROUND IS BAKED, NOT LIVE — AND THAT WAS A MEASUREMENT, NOT A
   PREFERENCE. The Physarum network that draws it (js/mold.js, still used by
   lab/) costs **42 ms per step** at the resolution this composition needs
   (467×300 cells, 22k particles, measured in headless Chrome on this machine).
   At 15fps that is six times a whole second of CPU per second: it cannot run,
   and trying would peg a core for something no visitor watches. This project
   has already shipped one main-thread freeze from exactly that reasoning.

   So it is rendered once, offline — `lab/_bake.html`, ~1100 steps at grid
   900×522 — and stored as an alpha WebP. The simulation is toroidal, so the
   image is seamless; #field is fixed and covers exactly one viewport, so it
   never repeats and never scrolls against the type.

   The gradient mask quiets the left two-fifths, where every page's type sits.
   It replaces the per-frame text-safe masking the live version did. */
#field{position:fixed;inset:0;width:100%;height:100%;display:block;
       /* ⚠️ A BAKED LAYER CANNOT DODGE THE TYPE, so it has to be quiet enough
          not to need to. The live version ran at .55 because it re-measured
          every [data-field-safe] rectangle each frame and erased itself there;
          at that strength a static image puts filaments straight through the
          right-hand column of the Client R&D section. */
       z-index:0;pointer-events:none;opacity:.07;
       background:url(../assets/mold-bg.webp) center center/cover no-repeat;
       /* ⚠️ NO DIRECTIONAL MASK. Quieting one side was tried and is wrong
          here: the Client R&D section puts type on the LEFT and the RIGHT, so
          whichever side the gradient favours is a side with words on it. A
          uniform, genuinely faint layer is the only version that cannot pick
          a fight — and .1 is set by the contrast floor, not by taste
          (see the note above --ink-soft). A soft vignette keeps the corners
          from reading as a rectangle. */
       -webkit-mask-image:radial-gradient(120% 130% at 50% 45%,#000 55%,rgba(0,0,0,.55) 100%);
       mask-image:radial-gradient(120% 130% at 50% 45%,#000 55%,rgba(0,0,0,.55) 100%)}
@media (max-width:760px){
  /* one column of type and no margin to spare */
  #field{opacity:.05}
}
.site-header,main,.site-footer{position:relative;z-index:1}
/* THE PLATE — the ink figure from the social card (og-pinheiro-v2.png),
   reused as the hero's only image. It is stored as an ALPHA MASK, not as the
   card: the card carries type, and the crop that avoids the type also cuts the
   figure. As a mask the figure takes a palette colour instead of the card's
   grey, its left edge is feathered so the crop seam cannot show, and it costs
   one channel instead of three. It sits behind everything and reads at about
   a fifth strength — the hero's weight is the sentence, not this. */
.plate{position:absolute;top:0;bottom:0;right:min(-4vw,-40px);
       width:min(56vw,720px);pointer-events:none;z-index:0;
       background:linear-gradient(155deg,var(--fig-warm),var(--accent) 52%,var(--fig-r3));
       -webkit-mask:url(../assets/plate-mask.png) right center/contain no-repeat;
       mask:url(../assets/plate-mask.png) right center/contain no-repeat;
       opacity:.30}
@media (max-width:760px){
  /* one column of type and no margin to spare: the plate drops back to a stain */
  .plate{width:88vw;right:-26vw;opacity:.11}
}
.hero-inner{position:relative;z-index:1;max-width:var(--maxw);margin:0 auto;width:100%}
/* NOT ch: this container's font is the body face, so a ch measure here sizes
   the column against 1rem and squeezes the display type into a sixth of the
   width it needs. */
.hero-text{max-width:min(50vw,600px)}
.hero h1{margin:20px 0 22px}
.hero-note{margin-top:clamp(34px,6vh,60px);color:var(--ink-faint);letter-spacing:.14em;
           line-height:1.8;max-width:38ch}
.hero .sub{max-width:34ch;color:var(--ink-soft);margin-bottom:34px}
html:not([data-js="on"]) .hero-fallback{position:absolute;inset:auto var(--gutter) 50% auto;z-index:0}

/* ---------------------------------------------------------------- bands */
.band{padding:var(--band) var(--gutter);border-top:1px solid var(--rule)}
.band-inner{max-width:var(--maxw);margin:0 auto}
.band-head{display:flex;align-items:baseline;gap:18px;flex-wrap:wrap;margin-bottom:clamp(30px,5vh,54px)}
.band-head .eyebrow{flex:0 0 auto}

/* ---------------------------------------------------------------- the cycle
   Research → Development → Test → Learn, drawn as a circle because the model
   returns: what a test sends back is evidence, and evidence starts the next
   question. A row of four columns with an arrow after each says "then, then,
   then"; a ring says "again", which is the whole point.

   The four stages are an ORDERED LIST placed into a 3×3 grid — north, east,
   south, west — so the sequence survives with CSS off and reads correctly to a
   screen reader. The ring and the rosette are decoration, absolutely
   positioned, and marked aria-hidden.

   The rosette inside is a quasiperiodic tiling (docs/make-rosette.py): a
   pattern with fivefold symmetry that comes back around without ever repeating
   itself. That is the same statement as the ring, made in a figure.
   ------------------------------------------------------------------------- */
.cycle{position:relative;display:flex;justify-content:center;
       padding:clamp(8px,2vh,26px) 0}
.cycle-ring,.cycle-rosette{
  position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  pointer-events:none;
}
.cycle-ring{width:min(46vw,430px);aspect-ratio:1;color:var(--ink-ghost)}
.cycle-rosette{width:min(31vw,290px);opacity:.6;
               /* the rosette is a figure, so it may take a figure colour */
               filter:sepia(.5) saturate(1.5) hue-rotate(-8deg)}

.cycle-stages{
  list-style:none;display:grid;width:min(100%,1060px);
  grid-template-columns:minmax(0,1fr) min(46vw,430px) minmax(0,1fr);
  grid-template-rows:auto min(46vw,430px) auto;
  align-items:center;justify-items:center;gap:clamp(10px,1.6vw,22px);
}
.stage{max-width:30ch}
.stage--n{grid-area:1/2;text-align:center}
.stage--e{grid-area:2/3;text-align:left}
.stage--s{grid-area:3/2;text-align:center}
.stage--w{grid-area:2/1;text-align:right}
.stage-i{font-family:var(--font-mono);font-size:10px;letter-spacing:.16em;
         color:var(--accent);display:block;margin-bottom:8px}
.stage-name{font-family:var(--font-display);font-size:clamp(1.25rem,2vw,1.6rem);
            display:block;margin-bottom:6px}
.stage-say{color:var(--ink-soft);display:block;font-size:.96rem}
.model-loop{margin-top:clamp(20px,3vh,34px);color:var(--ink-faint);
            letter-spacing:.14em;text-align:center}

/* Below the point where a ring has room for text on four sides, the stages
   become the ordered list they already are, and the ring steps aside. A circle
   squeezed into one column is a decoration pretending to be a diagram. */
@media (max-width:900px){
  .cycle-ring,.cycle-rosette{display:none}
  .cycle-stages{grid-template-columns:1fr;grid-template-rows:none;
                gap:clamp(20px,3.4vh,32px);justify-items:start}
  .stage{max-width:36ch}
  .stage--n,.stage--e,.stage--s,.stage--w{grid-area:auto;text-align:left}
  .stage{border-top:1px solid var(--rule);padding-top:14px}
  .model-loop{text-align:left}
}

/* -------------------------------------------------------- two origins, one loop
   The loop is the structure; the origins are annotations beside it. They are
   NOT a second product column — the strategy is explicit that audience work
   and applied work are not two symmetrical menus, and the applied path forks
   because an applied question may need investigating first or may already have
   enough behind it to start building.
   ------------------------------------------------------------------------- */
.cycle-wrap{display:grid;grid-template-columns:minmax(0,.72fr) minmax(0,1.5fr);
            gap:clamp(24px,4vw,72px);align-items:center}
/* ⚠️ The figure runs the FULL width of its column so its arrowheads finish at
   the column edge, a gutter away from the ring — they read as entering it.
   Squeezed into a narrow side column beside the labels they became a squiggle
   too small to see the fork in, and the fork is the only thing this drawing
   has to say. */
.origins-label{color:var(--ink-faint);letter-spacing:.2em;text-transform:uppercase;
               font-size:10px;margin:0 0 14px}
.or-svg{width:100%;height:auto;display:block;color:var(--ink);margin-bottom:20px}
.or-path{fill:none;stroke:currentColor;stroke-opacity:.34;stroke-width:1.3}
.or-path--b{stroke:var(--accent);stroke-opacity:.55;stroke-dasharray:4 3.5}
.or-head{fill:none;stroke:currentColor;stroke-opacity:.5;stroke-width:1.3;
         stroke-linecap:round;stroke-linejoin:round}
.or-head--b{stroke:var(--accent);stroke-opacity:.75}
.or-dot{fill:var(--ink);fill-opacity:.5}
.or-fork{fill:var(--accent)}
.origin-list{list-style:none;margin:0;padding:0;display:grid;gap:18px}
.origin{border-left:2px solid var(--rule);padding-left:14px}
.origin--b{border-left-color:var(--accent)}
.o-name{display:block;font-family:var(--font-display);font-size:1.06rem;
        line-height:1.2;margin-bottom:4px}
.o-say{display:block;color:var(--ink-soft);font-size:.9rem;line-height:1.45}
.o-to{display:block;margin-top:6px;color:var(--ink-faint);letter-spacing:.12em;
      text-transform:uppercase;font-size:10px}

/* ------------------------------------------------------------ client R&D bridge
   ⚠️ THIS REPLACED A SANKEY, ON PURPOSE. The ribbon widths in that diagram were
   real counts, but the picture still read as a claim about flow and implied
   that every research module continues into development. It does not: a
   research-only engagement is legitimate, and which module leads to which
   family is not something anyone here can honestly route. So the middle is one
   CONDITIONAL GATE — three modules in, one labelled rail, four families out,
   every line dashed because it is a possibility and not a pipeline.
   The old diagram and its generator are archived in versions/.
   ------------------------------------------------------------------------- */
.bridge{display:grid;grid-template-columns:minmax(0,1fr) minmax(120px,.42fr) minmax(0,1fr);
        gap:clamp(18px,2.4vw,40px);align-items:stretch}
.col{list-style:none;margin:0;padding:0;display:grid}
/* ⚠️ Equal rows, because the bridge's end points are generated at (i+0.5)/3
   and (i+0.5)/4 of its height. Change the row count in one and the other must
   change with it or every curve lands between two cells. */
.col--research{grid-template-rows:repeat(3,1fr)}
.col--dev{grid-template-rows:repeat(4,1fr)}
.cell{padding:14px 0;border-top:1px solid var(--rule);align-self:stretch}
.col--dev .cell{text-align:right}
.cell-i{display:block;font-size:10px;letter-spacing:.16em;color:var(--accent);
        margin-bottom:6px}
.cell h3{margin:0 0 6px;font-size:clamp(1.02rem,1.5vw,1.22rem)}
.cell p{margin:0;color:var(--ink-soft);font-size:.88rem;line-height:1.45}
.cell-eg{margin-top:8px !important;color:var(--ink-faint) !important;
         opacity:.5;transition:opacity .3s ease}
.cell:hover .cell-eg,.cell:focus-within .cell-eg{opacity:1}
.cell-eg .mono{font-size:10px;letter-spacing:.14em;text-transform:uppercase;
               color:var(--accent);margin-right:6px}

.bridge-mid{position:relative;display:flex;flex-direction:column;
            align-items:center;justify-content:center}
.br-svg{width:100%;height:100%;max-height:420px;display:block;color:var(--ink)}
.br-in,.br-out{fill:none;stroke:currentColor;stroke-opacity:.34;stroke-width:1.1;
               stroke-dasharray:4 4}
.br-rail{stroke:var(--accent);stroke-opacity:.55;stroke-width:1.6;fill:none}
.br-gate{fill:none;stroke:var(--accent);stroke-width:1.6}
/* Knocked out of the paper, not floated on top of the curves — without the
   background the dashed lines run straight through the words and read as a
   strikethrough. */
.bridge-label{position:absolute;left:50%;top:50%;transform:translate(-50%,24px);
              text-align:center;color:var(--accent);letter-spacing:.12em;
              text-transform:uppercase;font-size:10px;line-height:1.7;
              white-space:nowrap;background:var(--paper);padding:5px 8px}
.band-say{color:var(--ink-soft);max-width:44ch;margin:10px 0 0}
.band-note{margin-top:clamp(22px,3vh,36px);color:var(--ink-faint);
           letter-spacing:.12em;text-transform:uppercase;font-size:var(--fs-label)}
.band-head-block{margin-bottom:clamp(28px,4.5vh,52px)}
.band-head-block .band-head{margin-bottom:0}

/* ------------------------------------------------------------------------ lab
   ⚠️ NO PLACEHOLDER PROJECT CARDS. The brief is explicit — only real projects,
   and `Lab` stays out of the nav until one exists. The section says what the
   Lab is and shows the shape a project takes; the empty state is the content.
   ------------------------------------------------------------------------- */
.lab-shape{border-top:1px solid var(--rule);padding-top:22px;
           display:grid;grid-template-columns:minmax(0,.5fr) minmax(0,1fr);
           gap:clamp(20px,3vw,52px);align-items:start}
.lab-trace{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;
           gap:6px 0;color:var(--ink-faint);letter-spacing:.14em;
           text-transform:uppercase;font-size:10px;align-items:center}
.lab-trace li + li::before{content:"→";margin:0 8px;color:var(--ink-ghost)}
.lab-empty{margin:0;color:var(--ink-soft);max-width:46ch}

/* -------------------------------------------------------------- method teaser */
.teaser .band-inner{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
                    gap:clamp(28px,4vw,72px);align-items:center}
.teaser-fig{display:grid;justify-items:center}
.in-svg{width:100%;max-width:220px;height:auto;display:block;color:var(--ink)}
.in-ring{fill:none;stroke:currentColor;stroke-opacity:.14;stroke-width:1}
.in-spoke{stroke:currentColor;stroke-opacity:.3;stroke-width:1.2;fill:none}
.in-spoke--built{stroke:var(--accent);stroke-opacity:.7;stroke-dasharray:3.5 3}
.in-end{fill:var(--ink);fill-opacity:.4}
.in-end--built{fill:none;stroke:var(--accent);stroke-width:1.5}
.in-core{fill:var(--ink)}
.teaser-cap{margin-top:16px;text-align:center;color:var(--ink-faint);
            letter-spacing:.1em;font-size:10px;line-height:1.8}
.cta--quiet{border-bottom-color:var(--hairline)}
.hero-cta{margin-top:clamp(28px,4vh,46px)}
.closing-say{color:var(--ink-soft);max-width:40ch;margin:0 0 26px}

@media (max-width:1000px){
  /* Stacked inputs above a compact loop — the brief's own recomposition. A
     three-column bridge at phone width is a smear, so the gate drops out and
     the two columns become two lists with the condition stated between them. */
  .cycle-wrap{grid-template-columns:1fr;gap:clamp(24px,4vh,44px)}
  .or-svg{max-width:210px}
  .bridge{grid-template-columns:1fr;gap:clamp(20px,3vh,34px)}
  .br-svg{display:none}
  .bridge-mid{order:2;min-height:0;padding:6px 0}
  .bridge-label{position:static;transform:none;white-space:normal;text-align:left;
                border-left:2px solid var(--accent);padding-left:14px}
  .col--research{order:1}
  .col--dev{order:3}
  .col--research,.col--dev{grid-template-rows:none;gap:0}
  .col--dev .cell{text-align:left}
  .lab-shape,.teaser .band-inner{grid-template-columns:1fr}
  .teaser-fig{justify-items:start}
  .teaser-cap{text-align:left}
}
@media (hover:none){
  .cell-eg{opacity:1}
}

/* ---------------------------------------------------------------- founder + cta */
.founder{max-width:52ch}
.founder .who{font-family:var(--font-display);font-size:1.2rem;margin-bottom:.35em}
.founder .who .mono{margin-left:.9em;white-space:nowrap}
.founder p + p{margin-top:.2em}
.closing h2{max-width:16ch;margin-bottom:24px}
.closing .founder{margin-bottom:clamp(44px,7vh,84px)}

/* ---------------------------------------------------------------- footer */
.site-footer{
  border-top:1px solid var(--rule);
  padding:clamp(34px,5vh,56px) var(--gutter) clamp(30px,4vh,46px);
  display:flex;flex-wrap:wrap;gap:12px 32px;align-items:baseline;color:var(--ink-faint);
}
.site-footer a{color:var(--ink-soft);text-decoration:none}
.site-footer a:hover{color:var(--ink)}
/* 2026-09-11 — A ASSINATURA DO FOUNDER. Saiu da secção final da homepage e é
   agora um colofão em todas as páginas: linha inteira por cima da fila mono,
   o nome na serifa do site e a bio pequena a seguir — uma assinatura, não uma
   segunda apresentação. (O rodapé é igual byte a byte em todas as páginas:
   mudar aqui é mudar em todas, e o texto está escrito à mão em cada <footer>.) */
.site-footer .ft-founder{flex:1 1 100%;margin:0 0 clamp(8px,1.4vh,16px);max-width:none;
  display:flex;flex-wrap:wrap;align-items:baseline;gap:.25em .9em}
.site-footer .ft-name{font-family:var(--font-display);font-size:clamp(1.05rem,1.4vw,1.25rem);
  color:var(--ink);letter-spacing:-.005em}
.site-footer .ft-bio{font-size:.86rem;line-height:1.55;color:var(--ink-soft);max-width:64ch}

/* ---------------------------------------------------------------- inner pages */
.page-head{padding:clamp(140px,20vh,200px) var(--gutter) clamp(40px,6vh,72px)}
.page-head h1{max-width:15ch;margin:18px 0 20px;font-size:clamp(2.1rem,4.6vw,3.4rem)}
.page-head .lede{font-family:var(--font-display);font-size:clamp(1.1rem,1.6vw,1.35rem);
                 line-height:1.45;max-width:46ch;color:var(--ink)}
/* ⚠️ 2026-09-13: duas ledes seguidas (a frase principal e a de apoio) ficavam
   coladas — liam-se como um parágrafo só. Uma linha de ar entre elas. */
.page-head .lede + .lede{margin-top:.75em}
.prose{max-width:var(--maxw);margin:0 auto;display:grid;
       grid-template-columns:minmax(120px,1fr) minmax(0,3fr);gap:clamp(20px,3.4vw,56px)}
.prose > .rail{color:var(--ink-faint);font-family:var(--font-mono);font-size:var(--fs-label);
               letter-spacing:.18em;text-transform:uppercase;line-height:1.8}
.prose-body > * + *{margin-top:1.15em}
.prose-body h2{margin-bottom:.4em}
.claim{font-family:var(--font-display);font-size:clamp(1.1rem,1.6vw,1.3rem);line-height:1.45}
.list-inline{color:var(--ink-soft)}

.figures{display:flex;flex-wrap:wrap;gap:clamp(20px,4vw,54px);align-items:flex-end;
         margin-top:1.6em;padding-top:1.4em;border-top:1px solid var(--hairline)}
.figure-num{font-family:var(--font-mono);font-weight:500;font-size:clamp(1.7rem,3.4vw,2.6rem);
            line-height:1;display:block}
.figure-num--out{color:var(--accent)}
.figure-cap{font-family:var(--font-mono);font-size:10px;letter-spacing:.16em;
            text-transform:uppercase;color:var(--ink-faint);display:block;margin-top:9px}

/* signals table on Method — a ladder of what each trace can actually imply */
.signals{margin-top:1.4em;border-top:1px solid var(--hairline)}
.signal{display:grid;grid-template-columns:30px minmax(0,12ch) minmax(0,1fr);
        gap:clamp(10px,2vw,26px);align-items:baseline;padding:13px 0;
        border-bottom:1px solid var(--rule)}
.signal .n{font-family:var(--font-mono);font-size:10px;color:var(--ink-faint);letter-spacing:.1em}
.signal .what{font-family:var(--font-mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase}
.signal .means{color:var(--ink-soft)}
.signal:last-child .what{color:var(--accent)}
@media (max-width:640px){
  .signal{grid-template-columns:26px 1fr;row-gap:4px}
  .signal .means{grid-column:2}
}

/* ------------------------------------------- About: selected experience --
   ⚠️ 2026-09-13 (handoff v5 §8): uma lista editorial compacta, NÃO um LinkedIn.
   Organização + papel + datas à esquerda, uma frase à direita; réguas finas,
   sem cartões. Nada aqui deve crescer para escala de display: o §26 proíbe
   biografia em tamanho de título. */
.ab-list{list-style:none;margin:1.4em 0 0;padding:0;border-top:1px solid var(--rule)}
.ab-item{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.35fr);
         gap:4px clamp(16px,3vw,44px);align-items:baseline;
         padding:clamp(14px,2vh,20px) 0;border-bottom:1px solid var(--rule)}
.ab-org{font-family:var(--font-display);font-size:1.14rem;line-height:1.2;margin:0}
.ab-role{margin:.25em 0 0;color:var(--ink-soft)}
.ab-when{font-family:var(--font-mono);font-size:10px;letter-spacing:.16em;
         text-transform:uppercase;color:var(--ink-faint);margin:.5em 0 0}
.ab-note{margin:0;color:var(--ink-soft);font-size:.95rem;line-height:1.6}
.ab-links{display:flex;flex-wrap:wrap;gap:14px clamp(20px,3vw,34px);margin-top:1.7em}
.ab-links .cta{margin:0}
/* Experiência em formato simples (2026-09-14): organização e área numa linha,
   réguas finas, sem cargos nem datas. */
.ab-roles{list-style:none;margin:0;padding:0;border-top:1px solid var(--rule)}
.ab-roles li{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 18px;
             padding:clamp(12px,1.8vh,16px) 0;border-bottom:1px solid var(--rule)}
.ab-roles .ab-org{min-width:12rem}
.ab-roles .ab-area{color:var(--ink-soft)}

/* ------------------------------------------------------ About: o retrato --
   ⚠️ 2026-09-13: um círculo pequeno, a pedido do Vitor (ficheiro 400×400).
   Pequeno é a decisão de desenho: o §26 do handoff proíbe escala de cartaz
   para biografia, e a página abre com o nome, não com a cara. O círculo entra
   antes do rótulo "About" e fica no ritmo do `.page-head`, com a mesma régua
   fina do resto da página em vez de moldura.
   ⚠️ `onerror` REMOVE A FIGURA. Enquanto o ficheiro não estiver em
   assets/vitor-400.jpg a página publica-se limpa, sem ícone de imagem
   partida e sem buraco no layout — o Vitor pediu explicitamente que não
   ficassem placeholders por publicar. É também a razão de não haver aqui
   `background` de espera: um círculo cinzento é um placeholder.
   ⚠️ `width`/`height` no HTML + `aspect-ratio` aqui: a caixa é reservada
   antes de a imagem chegar, senão o título salta quando ela carrega. */
.ab-portrait{margin:0 0 clamp(18px,2.6vw,28px);width:clamp(84px,9vw,116px);aspect-ratio:1}
.ab-portrait img{display:block;width:100%;height:100%;border-radius:50%;
                 object-fit:cover;border:1px solid var(--hairline)}
@media (max-width:640px){
  .ab-item{grid-template-columns:1fr}
  .ab-note{margin-top:.6em}
}

/* ------------------------------------------------- Work: áreas + arquivo --
   §18: três colunas editoriais, sem listas de serviços. §19: um campo de
   arquivo deliberado — sem esqueletos, sem cartões cinzentos, sem "Project 01". */
.wk-areas{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
          gap:clamp(22px,3.4vw,56px)}
.wk-area{border-top:1px solid var(--rule);padding-top:1.1em}
.wk-label{font-family:var(--font-display);font-size:1.16rem;margin:0 0 .4em}
.wk-line{margin:0;color:var(--ink)}
.wk-micro{margin:.7em 0 0;color:var(--ink-faint);font-size:10px;letter-spacing:.14em;
          text-transform:uppercase;line-height:1.7}
.ar-big{font-family:var(--font-display);font-size:clamp(1.9rem,3vw,3rem);line-height:1.08;
        letter-spacing:-.01em;margin:0 0 .5em}
.ar-tags{list-style:none;display:flex;flex-wrap:wrap;gap:.5em clamp(18px,3vw,40px);
         margin:1.6em 0 0;padding:1.2em 0 0;border-top:1px solid var(--hairline);
         font-family:var(--font-mono);font-size:10px;letter-spacing:.16em;
         text-transform:uppercase;color:var(--ink-faint)}
@media (max-width:760px){
  .wk-areas{grid-template-columns:1fr;gap:clamp(20px,4vw,30px)}
}

/* ---------------------------------------------------------------- form */
.intake{max-width:620px}
.field{margin-bottom:clamp(24px,3vh,34px)}
.field-label{display:block;color:var(--ink-soft);margin-bottom:9px}
.field-label .n{color:var(--accent);margin-right:10px}
.intake input,.intake textarea{
  width:100%;font-family:var(--font-body);font-size:1.02rem;color:var(--ink);
  background:transparent;border:none;border-bottom:1px solid var(--hairline);
  padding:8px 0 10px;line-height:1.55;resize:none;
}
.intake textarea{min-height:3.2em;overflow:auto}
.field-help{margin:6px 0 0;color:var(--ink-faint);font-size:.84rem}
.lede--sub{color:var(--ink-faint)}
/* The progress rail names the shape of the brief before the visitor starts —
   five moves, not a sales funnel. aria-hidden because the numbered labels below
   already carry the sequence to a screen reader. */
.rail-steps{list-style:none;margin:0 0 clamp(26px,4vh,44px);padding:0 0 14px;
            display:flex;flex-wrap:wrap;gap:4px 0;align-items:center;
            border-bottom:1px solid var(--rule);color:var(--ink-faint);
            letter-spacing:.14em;text-transform:uppercase;font-size:10px}
.rail-steps li + li::before{content:"→";margin:0 8px;color:var(--ink-ghost)}
.intake input:focus,.intake textarea:focus{border-bottom-color:var(--accent)}
.intake input:focus:not(:focus-visible),.intake textarea:focus:not(:focus-visible){outline:none}
.intake ::placeholder{color:var(--ink-faint)}
.submit{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.18em;
  text-transform:uppercase;background:var(--ink);color:var(--paper);
  border:1px solid var(--ink);padding:14px 26px;cursor:pointer;
  transition:background .18s ease,border-color .18s ease;
}
.submit:hover{background:var(--accent);border-color:var(--accent)}
.form-note{margin-top:20px;color:var(--ink-soft);font-size:.93rem}
.form-sent{border:1px solid var(--turquoise);background:rgba(31,110,103,.06);
           padding:18px 22px;margin-bottom:1.8em}
.hp{position:absolute;left:-9999px}

/* ---------------------------------------------------------------- mobile */
@media (max-width:900px){
  .system-grid{grid-template-columns:1fr;gap:clamp(26px,5vh,44px)}
  .system-links{display:none}          /* curves need two columns to connect */
  .prose{grid-template-columns:1fr;gap:10px}
}
@media (max-width:760px){
  .site-header{padding:18px var(--gutter);align-items:center}
  .nav-toggle{display:block;font-family:var(--font-mono);font-size:var(--fs-label);
              letter-spacing:.18em;text-transform:uppercase}
  /* The collapse only happens once JS has said it can: without it the toggle
     is dead and the entire navigation would be unreachable on a phone. */
  html[data-js="on"] .site-nav{display:none;position:absolute;top:100%;left:0;right:0;
            flex-direction:column;gap:0;background:var(--paper);
            border-bottom:1px solid var(--rule);padding:4px var(--gutter) 16px}
  html[data-js="on"] .site-nav.open{display:flex}
  html:not([data-js="on"]) .nav-toggle{display:none}
  html:not([data-js="on"]) .site-nav{gap:0 18px;flex-wrap:wrap}
  .site-nav .navlink{padding:11px 0;border-bottom:1px solid var(--rule)}
  .site-nav .navlink:last-child{border-bottom:none}
  .hero{min-height:92svh;align-items:flex-end}
  .hero-text{max-width:none}
  .hero .sub{max-width:none}
    p{max-width:none}
}
@media (prefers-reduced-motion:reduce){
  .system-links path,.methods li,.node{transition:none!important}
}

/* ------------------------------------------------------ About: a deriva (2026-09-15)
   A biografia como trajeto, escolhida entre seis versões. Cada paragem num desvio
   diferente — o caminho não é uma coluna — e uma linha fina (svg, desenhada no
   about.html) liga os pontos. Abaixo de 700px as paragens alinham à esquerda e a
   linha continua a ligá-las. */
.av{ position:relative; }
.av p{ max-width:none; }
.av .cta{ margin:0; }
.av-face{ display:block; width:clamp(64px,7vw,96px); height:auto; aspect-ratio:1; border-radius:50%;
  object-fit:cover; border:1px solid var(--hairline); }
.av-links{ display:flex; flex-wrap:wrap; gap:12px 28px; margin-top:1.4em; }
.av-eyebrow{ font-family:var(--font-mono); font-size:var(--fs-label); letter-spacing:.18em;
  text-transform:uppercase; color:var(--ink-faint); display:block; }
.av2-head{ display:flex; gap:clamp(18px,2.5vw,32px); align-items:center;
  padding:clamp(130px,19vh,190px) var(--gutter) clamp(40px,7vh,80px); }
.av2-head h1{ margin:.35em 0 .2em; font-size:clamp(2.1rem,4.4vw,3.4rem); }
.av2-sub{ margin:0; color:var(--ink-soft); font-size:1.02rem; }
.av2-path{ list-style:none; margin:0; padding:clamp(30px,6vh,60px) var(--gutter) clamp(90px,14vh,160px);
  position:relative; z-index:1; }
.av2-stop{ position:relative; max-width:36ch; padding-left:34px; margin:0 0 clamp(70px,14vh,150px); }
.av2-stop:nth-child(1){ margin-left:4%; }
.av2-stop:nth-child(2){ margin-left:40%; }
.av2-stop:nth-child(3){ margin-left:12%; }
.av2-stop:nth-child(4){ margin-left:48%; }
.av2-stop:nth-child(5){ margin-left:18%; }
.av2-stop:nth-child(6){ margin-left:36%; margin-bottom:0; }
.av2-stop p + p{ margin-top:.7em; }
/* a frase-chave da prática: maior, em itálico, na cor da tinta */
.av2-quote{ font-family:var(--font-display); font-style:italic; color:var(--ink) !important;
  font-size:clamp(1.3rem,2.1vw,1.75rem); line-height:1.25 !important; }
.av2-dot{ position:absolute; left:0; top:1.9em; width:11px; height:11px; border-radius:50%;
  background:var(--accent); box-shadow:0 0 0 5px var(--paper); }
.av2-when{ display:block; font-family:var(--font-mono); font-size:.68rem; letter-spacing:.16em;
  text-transform:uppercase; color:var(--accent); margin-bottom:.55em; }
.av2-stop h2{ margin:0 0 .35em; font-size:clamp(1.3rem,2vw,1.7rem); }
.av2-stop p{ margin:0; color:var(--ink-soft); line-height:1.6; }
.av2-note{ margin-top:.6em !important; font-size:.9rem; }
.av2-figs{ margin-top:.9em !important; font-family:var(--font-mono); font-size:.7rem; letter-spacing:.12em;
  text-transform:uppercase; line-height:2; }
.av2-figs span{ display:block; color:var(--ink-faint); }
.av2-figs b{ color:var(--accent); font-weight:500; margin:0 .3em 0 1em; }
.av2-figs span + b{ margin-left:0; }
.av2-line{ position:absolute; left:0; top:0; pointer-events:none; z-index:0; overflow:visible; }
.av2-line path{ fill:none; stroke:var(--ink-ghost); stroke-width:1.2; }
@media (max-width:700px){
  .av2-stop:nth-child(n){ margin-left:0; }
  .av2-head{ flex-direction:column; align-items:flex-start; }
}

