/* ============================================================================
   Gabriel Fialho, portfolio
   ----------------------------------------------------------------------------
   The design has one idea: every claim on this site carries its status.
   Something is either measured, and then the number is there, or it is not, and
   then the page says so. That distinction is the accent system, so the honesty
   is structural rather than a paragraph promising honesty.

   Palette is instrument, not editorial: cool paper, graphite, one teal for
   measured and one amber reserved exclusively for unmeasured. Amber never
   appears as decoration. If you see it, something is unverified.
   ========================================================================= */

/* ---------------------------------------------------------------- tokens -- */

:root {
  --paper:      #f7f9fb;
  --paper-2:    #ffffff;
  --paper-3:    #edf1f5;
  --ink:        #101418;
  --ink-2:      #39434e;
  --graphite:   #5a6673;
  --rule:       #dce3ea;
  --rule-2:     #c3ced8;

  --measured:      #0d5f6e;
  --measured-bg:   #dcecef;
  --unmeasured:    #a8620a;
  --unmeasured-bg: #f6e9d8;

  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  --rail: 10.5rem;
  --col:  40rem;
  --gap:  3rem;
  --pad:  clamp(1.25rem, 4vw, 2.5rem);

  --t--2: .7rem;
  --t--1: .8125rem;
  --t-0:  1rem;
  --t-1:  1.1875rem;
  --t-2:  clamp(1.4rem, 1.2rem + .7vw, 1.8rem);
  --t-3:  clamp(1.9rem, 1.5rem + 1.6vw, 2.6rem);
  --t-4:  clamp(2.3rem, 1.6rem + 2.9vw, 3.6rem);

  --ease: cubic-bezier(.22, .61, .36, 1);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:    #0c1015;
    --paper-2:  #121820;
    --paper-3:  #0f151c;
    --ink:      #e6ebf0;
    --ink-2:    #b3bfcb;
    --graphite: #8b98a6;
    --rule:     #1e2833;
    --rule-2:   #2d3a47;
    --measured:      #4cbccd;
    --measured-bg:   #0e2b31;
    --unmeasured:    #dda13f;
    --unmeasured-bg: #2b2011;
  }
}

:root[data-theme="dark"] {
  --paper:    #0c1015;
  --paper-2:  #121820;
  --paper-3:  #0f151c;
  --ink:      #e6ebf0;
  --ink-2:    #b3bfcb;
  --graphite: #8b98a6;
  --rule:     #1e2833;
  --rule-2:   #2d3a47;
  --measured:      #4cbccd;
  --measured-bg:   #0e2b31;
  --unmeasured:    #dda13f;
  --unmeasured-bg: #2b2011;
}

/* ------------------------------------------------------------------ base -- */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--t-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  margin: 0;
  font-weight: 700;
  letter-spacing: -.035em;
  line-height: 1.1;
  text-wrap: balance;
}

p { margin: 0 0 1.1em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: inherit; }

code {
  font-family: var(--mono);
  font-size: .86em;
  background: var(--paper-3);
  border-radius: 3px;
  padding: .12em .34em;
}

img { max-width: 100%; height: auto; display: block; }

::selection { background: var(--measured); color: var(--paper); }

:focus-visible { outline: 2px solid var(--measured); outline-offset: 3px; }

.skip { position: absolute; left: -9999px; }
.skip:focus {
  left: 0; top: 0; z-index: 99;
  background: var(--ink); color: var(--paper); padding: .7rem 1rem;
}

/* ---------------------------------------------------------------- layout -- */
/* One grid for the whole site: a narrow rail of metadata and a reading column.
   The rail is what fixes the balance problem of the first version, where prose
   hugged the left edge while rules ran the full width of the viewport. Here
   nothing is wider than the grid, so the page has one edge, not two. */

.grid {
  display: grid;
  grid-template-columns: var(--rail) minmax(0, var(--col));
  column-gap: var(--gap);
  max-width: calc(var(--rail) + var(--gap) + var(--col));
  margin-inline: auto;
  padding-inline: var(--pad);
}

.rail  { grid-column: 1; }
.col   { grid-column: 2; min-width: 0; }
.bleed { grid-column: 1 / -1; }

@media (max-width: 52rem) {
  .grid { grid-template-columns: minmax(0, 1fr); row-gap: .75rem; }
  .rail, .col, .bleed { grid-column: 1; }
}

.rail-label {
  font-family: var(--mono);
  font-size: var(--t--2);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--graphite);
  line-height: 1.7;
  margin: 0;
}

/* Label above value, so the rail reads as pairs instead of as one long list of
   shouting uppercase lines. */
.facts { display: grid; gap: .85rem; }
.fact dt {
  font-family: var(--mono);
  font-size: var(--t--2);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--graphite);
}
.fact dd {
  margin: .15rem 0 0;
  font-size: var(--t--1);
  line-height: 1.35;
  color: var(--ink-2);
}

section { padding-block: clamp(2.5rem, 6vw, 4.5rem); }
.divider { border: 0; border-top: 1px solid var(--rule); margin: 0; }

/* Section spacing variants. These exist as classes rather than inline styles so
   the site can ship a Content-Security-Policy without `unsafe-inline`, which is
   worth more than the convenience of a style attribute. */
.section--flush-bottom { padding-bottom: 0; }
.section--tight-top    { padding-top: 1rem; }
.section--tight-bottom { padding-bottom: 1rem; }
.section--roomy        { padding-block: 4rem 6rem; }

.cases { padding-block: 1.5rem 3rem; }

.section-intro { color: var(--graphite); font-size: var(--t-0); }
.page-title { font-size: var(--t-3); margin-bottom: 1rem; }
.note { color: var(--ink-2); margin-top: .9rem; }
.rail a { color: var(--measured); }

/* ------------------------------------------------------------------ head -- */

.site-head {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--paper) 90%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid transparent;
  transition: border-color .25s var(--ease);
}
.site-head[data-stuck="true"] { border-bottom-color: var(--rule); }

.head-inner {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  min-height: 3.25rem;
  max-width: calc(var(--rail) + var(--gap) + var(--col));
  margin-inline: auto;
  padding-inline: var(--pad);
}

.wordmark {
  font-family: var(--mono);
  font-size: var(--t--1);
  text-decoration: none;
  letter-spacing: -.01em;
}
.wordmark b { font-weight: 600; }
.wordmark span { color: var(--graphite); }
/* The role qualifier wraps the header onto two lines on a narrow phone, and the
   name alone carries the same information there. */
@media (max-width: 30rem) { .wordmark span { display: none; } }

.site-nav { display: flex; align-items: center; gap: 1.1rem; font-family: var(--mono); font-size: var(--t--2); }
.site-nav a { color: var(--graphite); text-decoration: none; letter-spacing: .05em; text-transform: uppercase; }
.site-nav a:hover { color: var(--ink); }

.theme-toggle {
  appearance: none; background: none; border: 0; padding: .25rem;
  color: var(--graphite); cursor: pointer; display: grid; place-items: center;
}
.theme-toggle:hover { color: var(--ink); }
.theme-toggle svg { width: .95rem; height: .95rem; }

/* Icon shows the theme you are in. Three states, each overriding the last. */
.theme-toggle .sun  { display: block; }
.theme-toggle .moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .theme-toggle .sun  { display: none; }
  :root:not([data-theme]) .theme-toggle .moon { display: block; }
}
:root[data-theme="dark"] .theme-toggle .sun  { display: none; }
:root[data-theme="dark"] .theme-toggle .moon { display: block; }

/* --------------------------------------------------------------- verdict -- */
/* The signature. A filled square means there is a number behind the claim; a
   hollow dashed circle means there is not, and that this is known. */

.verdict {
  display: inline-flex; align-items: center; gap: .45rem;
  font-family: var(--mono);
  font-size: var(--t--2);
  letter-spacing: .07em;
  text-transform: uppercase;
  white-space: nowrap;
}
.verdict::before { content: ""; width: .5rem; height: .5rem; flex: none; }

.verdict--measured { color: var(--measured); }
.verdict--measured::before { background: var(--measured); }

.verdict--open { color: var(--unmeasured); }
.verdict--open::before {
  border: 1.5px dashed var(--unmeasured);
  border-radius: 50%;
}

.portrait {
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  margin-bottom: 1.4rem;
  /* Ring drawn in CSS rather than baked into the file, so it follows the theme
     while the image itself stays one asset. */
  box-shadow: 0 0 0 1px var(--rule-2);
}

/* ------------------------------------------------------- experience -- */

.role { padding-block: 1.4rem; border-top: 1px solid var(--rule); }
.role:first-child { border-top: 0; padding-top: 0; }
.role h3 { font-size: var(--t-1); margin-bottom: .2rem; }
.role .when {
  font-family: var(--mono);
  font-size: var(--t--2);
  letter-spacing: .05em;
  color: var(--graphite);
}
.role p { margin: .7rem 0 0; color: var(--ink-2); font-size: var(--t--1); }

.chips { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .9rem; }
.chip {
  font-family: var(--mono);
  font-size: var(--t--2);
  color: var(--graphite);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: .2rem .5rem;
  white-space: nowrap;
}

/* ------------------------------------------------------------------ hero -- */

.hero { padding-block: clamp(2rem, 5vw, 3.25rem) clamp(2.5rem, 6vw, 4rem); }

.hero h1 {
  font-size: var(--t-4);
  margin-bottom: 1.25rem;
}
.hero .lede {
  font-size: var(--t-1);
  color: var(--ink-2);
  line-height: 1.5;
}

/* The ledger: the hero's thesis rendered as data rather than as a slogan. */
.ledger { margin-top: 2rem; border-top: 1px solid var(--rule); }
.ledger-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: .5rem 1.5rem;
  align-items: baseline;
  padding: .6rem 0;
  border-bottom: 1px solid var(--rule);
  font-size: var(--t--1);
}
.ledger-row span:first-child { color: var(--ink-2); }

/* ------------------------------------------------------------------ work -- */

.section-label {
  font-family: var(--mono);
  font-size: var(--t--2);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--graphite);
}

/* No `display` here. `.case` is also a `.grid`, and both are single-class
   selectors, so declaring display twice means the one written last silently
   wins. That bug put the rail on top of the heading instead of beside it. */
.case { text-decoration: none; padding-block: 2rem; border-top: 1px solid var(--rule); }
.case:first-of-type { border-top: 0; }

.case h2 {
  font-size: var(--t-2);
  margin-bottom: .6rem;
  transition: color .2s var(--ease);
}
.case:hover h2 { color: var(--measured); }
.case p { color: var(--ink-2); margin-bottom: .9rem; }

.case-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 1.25rem;
  font-family: var(--mono); font-size: var(--t--2); color: var(--graphite);
}
.case-foot .go { color: var(--measured); letter-spacing: .05em; text-transform: uppercase; }
.case:hover .go .arrow { transform: translateX(3px); }
.go .arrow { display: inline-block; transition: transform .2s var(--ease); }

.stack { display: grid; gap: .35rem; }

/* --------------------------------------------------------------- shipped -- */

.ships { display: grid; gap: 0; border-top: 1px solid var(--rule); }
.ship {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: .3rem 1rem;
  padding: 1.1rem 0;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
}
.ship h3 { font-family: var(--mono); font-size: var(--t-0); font-weight: 600; letter-spacing: -.01em; }
.ship[href]:hover h3 { color: var(--measured); }
.ship p { grid-column: 1 / -1; font-size: var(--t--1); color: var(--ink-2); margin: 0; }
.ship .meta { font-family: var(--mono); font-size: var(--t--2); color: var(--graphite); text-align: right; }

/* --------------------------------------------------------------- figures -- */

.figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: 1.25rem 1.5rem; margin-block: 1.75rem; }
.figure .n {
  font-size: var(--t-3);
  font-weight: 700;
  letter-spacing: -.04em;
  font-variant-numeric: tabular-nums;
  display: block;
  line-height: 1;
  margin-bottom: .4rem;
}
.figure .l { font-family: var(--mono); font-size: var(--t--2); color: var(--graphite); line-height: 1.5; display: block; }

/* --------------------------------------------------------------- diagram -- */

figure { margin: 2rem 0; }
figure img { width: 100%; }
figcaption {
  font-family: var(--mono);
  font-size: var(--t--2);
  color: var(--graphite);
  line-height: 1.6;
  margin-top: .6rem;
}

/* ----------------------------------------------------------------- prose -- */

.prose h2 { font-size: var(--t-2); margin: 2.5rem 0 .8rem; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { font-size: var(--t-0); font-weight: 650; letter-spacing: -.005em; margin: 1.6rem 0 .5rem; }
.prose ul { margin: 0 0 1.1em; padding-left: 1.1rem; }
.prose li { margin-bottom: .45em; }
.prose li::marker { color: var(--graphite); }
.prose a { color: var(--measured); text-underline-offset: 2px; }

pre {
  background: var(--paper-3);
  border: 1px solid var(--rule);
  border-radius: 6px;
  padding: 1rem 1.1rem;
  overflow-x: auto;
  font-family: var(--mono);
  font-size: var(--t--1);
  line-height: 1.6;
  margin-block: 1.5rem;
}
pre code { background: none; padding: 0; font-size: inherit; }

.table-scroll { overflow-x: auto; margin-block: 1.5rem; }
table { width: 100%; border-collapse: collapse; font-size: var(--t--1); }
th, td { text-align: left; padding: .6rem .8rem .6rem 0; border-bottom: 1px solid var(--rule); vertical-align: top; }
th { font-family: var(--mono); font-size: var(--t--2); letter-spacing: .05em; text-transform: uppercase; color: var(--graphite); font-weight: 500; }

/* The open block: where a case says what it does not know. It uses the amber,
   which appears nowhere else, so the page reads its own limits in one colour. */
.open {
  border-left: 2px solid var(--unmeasured);
  background: var(--unmeasured-bg);
  border-radius: 0 6px 6px 0;
  padding: 1.1rem 1.25rem;
  margin-block: 1.75rem;
}
.open .verdict { margin-bottom: .6rem; }
.open p { font-size: var(--t--1); color: var(--ink-2); }

/* ------------------------------------------------------------------ foot -- */

.case-nav {
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  padding-block: 2rem; border-top: 1px solid var(--rule); margin-top: 2.5rem;
  font-family: var(--mono); font-size: var(--t--2);
}
.case-nav a { color: var(--measured); text-decoration: none; }
.case-nav a:hover { text-decoration: underline; }

.links { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1.5rem; }
.btn {
  font-family: var(--mono); font-size: var(--t--1);
  text-decoration: none;
  border: 1px solid var(--rule-2); border-radius: 4px;
  padding: .5rem .9rem;
  transition: background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
.btn:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.btn--go { background: var(--measured); border-color: var(--measured); color: var(--paper-2); }
.btn--go:hover { background: var(--measured); border-color: var(--measured); color: var(--paper-2); filter: brightness(1.1); }

.site-foot {
  border-top: 1px solid var(--rule);
  padding-block: 1.75rem 2.5rem;
  font-family: var(--mono); font-size: var(--t--2); color: var(--graphite);
}
.site-foot a { color: var(--graphite); text-decoration: none; }
.site-foot a:hover { color: var(--measured); }

/* ---------------------------------------------------------------- motion -- */
/* One reveal, short travel. The first version staggered everything and the
   result read as a queue of animations rather than as a page arriving. */

.reveal { opacity: 0; transform: translateY(8px); transition: opacity .45s var(--ease), transform .45s var(--ease); }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; } }

@media print {
  .site-head, .theme-toggle, .case-nav, .site-foot { display: none; }
  body { background: #fff; color: #000; }
}
