/* romainbourre.fr — carte de visite letterpress (débossage encré + monogramme à sec).
   Fonts: Instrument Serif & IBM Plex Mono, self-hosted (SIL OFL 1.1, see assets/fonts).
   Light: --lx / --ly = position of the light relative to the card centre (unit-ish vector,
   screen coordinates, y down). Default: raking light from the top left. */

@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("assets/fonts/instrument-serif-regular-latin.woff2") format("woff2");
}

@font-face {
  font-family: "Instrument Serif";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("assets/fonts/instrument-serif-italic-latin.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("assets/fonts/ibm-plex-mono-500-latin.woff2") format("woff2");
}

@property --lx { syntax: "<number>"; inherits: true; initial-value: -0.6; }
@property --ly { syntax: "<number>"; inherits: true; initial-value: -0.8; }

:root {
  --table: #2a2825;
  --table-lit: #3b3833;
  --paper: #efe8da;
  --paper-floor: #e6ddcb;
  --paper-worst: #e3dac7; /* darkest expected paper (mottling + grain), for contrast checks */
  --edge-crease: #8a7759;
  --edge-1: #d6cbb6;
  --edge-2: #cbbfa8;
  --edge-3: #bfb198;
  --edge-4: #b0a084;
  --edge-5: #9a8868;
  --ink: #2a251f;
  --ink-2: #5b5246;
  --focus: #7a3218;

  --serif: "Instrument Serif", "Iowan Old Style", Palatino, Georgia, serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --lx: -0.6;
  --ly: -0.8;
  --la: 143deg; /* direction the light travels, for gradients; set by light.js */

  color-scheme: light;
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

html {
  background: var(--table);
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100svh;
  color: var(--ink);
  background:
    radial-gradient(
      /* fixed at the resting light (50% + lx/ly × 45%): the page never repaints with the light */
      120% 90% at 23% 14%,
      var(--table-lit) 0%,
      transparent 70%
    ),
    var(--table);
}

/* Matte table grain */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background: url("assets/textures/table.svg") 0 0 / 240px 240px;
  opacity: 0.5;
}

.table {
  position: relative;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 20px;
  min-height: 100vh;
  min-height: 100svh;
  padding: 24px;
}

/* ---------- The card ---------- */

.card {
  --thick: 6px;
  position: relative;
  isolation: isolate;
  container-type: inline-size;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "mark  domain"
    ".     ."
    "name  links";
  /* cq units cannot measure the container itself: padding and radius derive from its width. */
  --w: min(88vw, 80svh * 1.75, 1240px);
  width: var(--w);
  aspect-ratio: 1.75;
  padding: calc(var(--w) * 0.056) calc(var(--w) * 0.06) calc(var(--w) * 0.052);
  border-radius: calc(var(--w) * 0.005);
  background: var(--paper);
  box-shadow:
    /* lit top edge of the face */
    inset 0 1px 0 rgb(255 255 255 / 0.75),
    /* bottom arris of the face, catching the light */
    inset 0 -1px 0 rgb(255 252 244 / 0.6),
    /* the board's thickness, seen from the front: a dark crease, then light to shade */
    0 1px 0 var(--edge-crease),
    0 calc(var(--thick) / 3) 0 var(--edge-1),
    0 calc(var(--thick) / 2) 0 var(--edge-2),
    0 calc(var(--thick) * 2 / 3) 0 var(--edge-3),
    0 calc(var(--thick) * 5 / 6) 0 var(--edge-4),
    0 var(--thick) 0 var(--edge-5),
    /* contact shadow */
    0 calc(var(--thick) + 1px) 2px rgb(0 0 0 / 0.6),
    0 calc(var(--thick) + 3px) 6px -1px rgb(0 0 0 / 0.4),
    /* soft cast shadow, falls away from the light */
    calc(var(--lx) * -26px) calc(var(--ly) * -30px) 46px -8px rgb(0 0 0 / 0.5),
    calc(var(--lx) * -60px) calc(var(--ly) * -70px) 120px -30px rgb(0 0 0 / 0.45);
}

/* Paper layers sit under the type */
/* The paper carries its own background so the blended layers have something to blend with
   (it is a stacking context of its own). */
.card__paper {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  border-radius: inherit;
  pointer-events: none;
  background:
    linear-gradient(var(--la), rgb(255 253 247 / 0.5) 0%, rgb(255 253 247 / 0) 46%, rgb(92 70 40 / 0.06) 100%),
    radial-gradient(60% 50% at 78% 70%, rgb(205 190 160 / 0.14), transparent 70%),
    radial-gradient(40% 40% at 20% 85%, rgb(255 255 255 / 0.16), transparent 70%),
    var(--paper);
}

.paper__tooth,
.paper__fibres {
  position: absolute;
  inset: 0;
}

/* The same height field lit from the left (x) and from the top (y):
   their mix approximates N·L for any light in the top-left quadrant. */
.paper__tooth {
  mix-blend-mode: hard-light;
}

.paper__tooth--x {
  background: url("assets/textures/tooth-x.svg") 0 0 / 320px 320px;
  opacity: calc(max(0, var(--lx) * -1) * 0.32);
}

.paper__tooth--y {
  background: url("assets/textures/tooth-y.svg") 0 0 / 320px 320px;
  opacity: calc(max(0, var(--ly) * -1) * 0.32);
}

.paper__fibres {
  background: url("assets/textures/fibres.svg") 37px 11px / 600px 600px;
  opacity: 0.26;
  mix-blend-mode: multiply;
}

/* Fine speckle over everything, ink included: letterpress ink is never perfectly flat */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  pointer-events: none;
  background: url("assets/textures/grain.svg") 0 0 / 200px 200px;
  opacity: 0.14;
  mix-blend-mode: multiply;
}

/* ---------- Monogram: blind deboss ---------- */

/* The grid item is the monogram itself, or the button light.js may wrap it in. */
.card__mark,
.card__mark-button {
  grid-area: mark;
  align-self: start;
  justify-self: start;
  margin: -1.4cqi 0 0 -0.6cqi;
}

.card__mark {
  display: block;
  width: 17cqi;
  height: auto;
  overflow: visible;
  font-family: var(--serif);
  font-size: 150px;
  mix-blend-mode: hard-light;
}

/* Tilt permission (iOS-style API): the monogram is the control, and looks exactly the same. */
.card__mark-button {
  display: block;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  color: inherit;
  font: inherit;
  line-height: 0;
  appearance: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.card__mark-button > .card__mark {
  margin: 0;
}

.card__mark-button:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* ---------- Inked deboss ----------
   Pressed into the board: the wall facing the light is in shadow (offset towards the light),
   the far lip catches it (offset away). The ink colour alone carries the contrast. */

.card__name,
.card__title,
.card__domain,
.link__label,
.link__handle {
  text-shadow:
    calc(var(--lx) * var(--d)) calc(var(--ly) * var(--d)) calc(var(--d) * 0.8) rgb(64 46 24 / 0.42),
    calc(var(--lx) * var(--d) * -1.1) calc(var(--ly) * var(--d) * -1.1) calc(var(--d) * 0.5) rgb(255 253 246 / 0.95),
    calc(var(--lx) * var(--d) * -2.6) calc(var(--ly) * var(--d) * -2.6) calc(var(--d) * 3) rgb(255 250 236 / var(--halo, 0.5));
}

.card__domain {
  --d: 0.6px;
  --halo: 0;
  grid-area: domain;
  justify-self: end;
  margin: 0;
  font-family: var(--mono);
  font-size: max(13px, 1.12cqi);
  font-weight: 500;
  letter-spacing: 0.16em;
  color: var(--ink-2);
}

/* Name and title: one block, bottom left, the title subordinate to the name. */
.card__identity {
  grid-area: name;
  align-self: end;
}

.card__name {
  --d: 0.026em;
  margin: 0 0 0 -0.04em;
  font-family: var(--serif);
  font-size: 8.4cqi;
  font-weight: 400;
  line-height: 0.92;
  letter-spacing: -0.012em;
  color: var(--ink);
}

.name__last {
  font-style: italic;
}

/* Small capitals drawn from the source text (Plex Mono has none: synthesised, for this line only),
   never text-transform: read aloud and copied as written. 17px renders capitals the size of the
   12px LINKEDIN / GITHUB labels. */
.card__title {
  --d: 0.55px;
  --halo: 0;
  margin: 1.4cqi 0 0;
  font-family: var(--mono);
  font-size: max(17px, 1.4cqi);
  font-weight: 500;
  font-variant-caps: all-small-caps;
  font-synthesis-small-caps: auto;
  letter-spacing: 0.16em;
  line-height: 1.2;
  color: var(--ink-2);
}

.card__links {
  grid-area: links;
  align-self: end;
  display: grid;
  gap: 1.1cqi;
  justify-items: start;
}

.card__links a {
  display: grid;
  gap: 0.3cqi;
  min-height: 44px;
  margin: -6px -10px;
  padding: 6px 10px;
  border-radius: 4px;
  color: var(--ink);
  text-decoration: none;
}

.link__label {
  --d: 0.55px;
  --halo: 0;
  font-family: var(--mono);
  font-size: max(12px, 0.98cqi);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.link__handle {
  --d: 0.03em;
  font-family: var(--serif);
  font-size: max(20px, 2.15cqi);
  line-height: 1.1;
  text-decoration: underline;
  text-decoration-color: rgb(42 37 31 / 0.35);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
}

.card__links a:hover .link__handle {
  text-decoration-color: currentColor;
}

.card__links a:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* ---------- Portrait card on narrow / tall screens ---------- */

@media (max-aspect-ratio: 4/5) {
  .table {
    padding: 16px;
  }

  .card {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto minmax(0, 1fr) auto auto;
    grid-template-areas:
      "mark  domain"
      ".     ."
      "name  name"
      "links links";
    --w: min(100vw - 32px, (100svh - 96px) / 1.75, 520px);
    --thick: 4px;
    aspect-ratio: 1 / 1.75;
    padding: calc(var(--w) * 0.09) calc(var(--w) * 0.08) calc(var(--w) * 0.08);
    border-radius: calc(var(--w) * 0.01);
  }

  /* Smaller tile: fibres keep about the same physical size as on the landscape card. */
  .paper__fibres {
    background-size: 400px 400px;
  }

  .card__mark,
  .card__mark-button {
    margin: -2.6cqi 0 0 -1cqi;
  }

  .card__mark {
    width: 34cqi;
  }

  .card__domain {
    font-size: max(12px, 3.2cqi);
    letter-spacing: 0.12em;
  }

  .card__identity {
    margin-bottom: 10cqi;
  }

  .card__name {
    font-size: 19cqi;
  }

  .card__title {
    margin-top: 3.4cqi;
    font-size: max(17px, 4.6cqi);
    letter-spacing: 0.12em;
  }

  .name__first,
  .name__last {
    display: block;
  }

  .card__links {
    gap: 4cqi;
  }

  .link__label {
    font-size: max(12px, 3cqi);
  }

  .link__handle {
    font-size: max(20px, 6.4cqi);
  }
}

/* ---------- Preferences ---------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
  }
}

@media (forced-colors: active) {
  .card {
    border: 1px solid CanvasText;
    background: Canvas;
    box-shadow: none;
  }

  /* Nothing is lit in forced colours: the monogram goes, and the tilt control with it. */
  .card__paper,
  .card::after,
  .card__mark,
  .card__mark-button,
  body::before {
    display: none;
  }

  .card__name,
  .card__title,
  .card__domain,
  .link__label,
  .link__handle {
    color: CanvasText;
    text-shadow: none;
  }

  .card__links a {
    color: LinkText;
  }

  .card__links a .link__handle {
    color: LinkText;
  }

  .card__links a:focus-visible {
    outline-color: Highlight;
  }
}

@media print {
  html,
  body {
    background: #fff;
  }

  body::before,
  .card::after {
    display: none;
  }

  .card {
    box-shadow: none;
    border: 0.5pt solid #ccc;
  }
}
