/* ==========================================================================
   danielenespoli.com
   A single stylesheet, shared by the English and the Italian page.

   Structure
     1. Fonts
     2. Design tokens
     3. Reset and base
     4. Layout primitives
     5. Masthead
     6. Hero
     7. Sections and index entries
     8. About
     9. Areas of work
    10. Contact
    11. Colophon
    12. Preference queries and print
   ========================================================================== */


/* 1. Fonts ================================================================= */

/* Newsreader, subset to Latin and instanced to a single weight so that only
   the optical size axis remains. One file, 54 KB, self hosted: no third party
   request, no cookie, nothing to consent to. SIL Open Font License 1.1, see
   assets/fonts/OFL.txt. */
@font-face {
  font-family: "Newsreader";
  src: url("../fonts/newsreader-latin-opsz.woff2") format("woff2-variations"),
       url("../fonts/newsreader-latin-opsz.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-stretch: normal;
  /* optional: the browser either has the font ready within its short block
     period or keeps the fallback for this page load. It never swaps mid
     render, so the font can never contribute to Cumulative Layout Shift. */
  font-display: optional;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2010-2015, U+2018-201A,
                 U+201C-201E, U+2020-2022, U+2026, U+2030, U+2039-203A,
                 U+2044, U+20AC, U+2122, U+2212;
}

/* Metric matched stand in, so the fallback render sits on the same rhythm.
   Values derived from the shipped subset: 2000 upem, ascender 1470,
   descender 530, mean lowercase advance 0.4625 em, against Georgia. */
@font-face {
  font-family: "Newsreader Fallback";
  src: local("Georgia"), local("Times New Roman"), local("Liberation Serif"),
       local("Times"), local("DejaVu Serif");
  size-adjust: 92.5%;
  ascent-override: 79.5%;
  descent-override: 28.6%;
  line-gap-override: 0%;
}


/* 2. Design tokens ========================================================= */

:root {
  color-scheme: light dark;

  /* Type */
  --serif: "Newsreader", "Newsreader Fallback", Georgia, "Times New Roman",
           "Liberation Serif", serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, "Cascadia Mono", Menlo,
          Consolas, "Liberation Mono", monospace;

  --fs-micro: 0.6875rem;                                   /* 11px, mono caps */
  --fs-small: 0.8125rem;                                   /* 13px           */
  --fs-body: clamp(1.0625rem, 1.005rem + 0.26vw, 1.1875rem);   /* 17 to 19px */
  --fs-lead: clamp(1.1875rem, 1.075rem + 0.5vw, 1.4375rem);    /* 19 to 23px */
  --fs-h2: clamp(1.125rem, 1.06rem + 0.29vw, 1.3125rem);       /* 18 to 21px */
  --fs-name: clamp(2.5rem, 1.5rem + 4.6vw, 5.5rem);            /* 40 to 88px */

  --lh-body: 1.62;
  --lh-tight: 1.28;
  --track-caps: 0.12em;

  /* Space, on a 4px scale */
  --pad: 1.25rem;
  --gutter: clamp(1.25rem, 0.5rem + 2.4vw, 2.5rem);
  --rhythm: clamp(3rem, 1.6rem + 5.4vw, 6rem);      /* between sections      */
  --maxw: 64rem;
  --col-ord: 3.5rem;                                 /* the margin column     */
  --measure: 34rem;                                  /* prose measure         */

  /* Colour: warm paper, one ink, one rubric.
     The greys are declared once as --ink-* and only ever read from there.
     Custom properties resolve at computed value time, so a media query that
     both reads and rewrites the same token would collapse the whole scale
     onto one value. Keeping the sources separate makes the high contrast
     block below safe to write. */
  --bg: #F7F5F0;
  --surface: #F1EEE7;
  --text: #14120F;
  --ink-70: #635C51;
  --ink-30: #B6AE9F;
  --ink-15: #DAD4C8;
  --accent: #A33520;
  --selection: #E9DCC4;

  --muted: var(--ink-70);
  --rule: var(--ink-15);
  --rule-strong: var(--ink-30);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #131211;
    --surface: #1C1B18;
    --text: #EBE7DE;
    --ink-70: #9C958A;
    --ink-30: #4A453D;
    --ink-15: #322F2A;
    --accent: #E4795C;
    --selection: #3A2A21;
  }
}


/* 3. Reset and base ======================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* keep a section heading clear of the top rule when jumped to */
  scroll-padding-top: 3rem;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--serif);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-optical-sizing: auto;
  font-variant-numeric: lining-nums tabular-nums;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

::selection { background: var(--selection); color: var(--text); }

h1, h2, p, dl, dd, figure, ul { margin: 0; }
dd { margin-inline-start: 0; }

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

a { color: inherit; }

a:focus-visible,
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 1px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10;
  padding: 0.65rem 1rem;
  background: var(--bg);
  border: 1px solid var(--accent);
  font-family: var(--mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  text-decoration: none;
}
.skip:focus { left: var(--pad); top: 0.75rem; }

.u-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* 4. Layout primitives ===================================================== */

.wrap {
  width: min(100% - (var(--pad) * 2), var(--maxw));
  margin-inline: auto;
}

/* The page grid: a narrow margin column that carries metadata (the role in
   the hero, the ordinal in every section) and a body column that carries the
   content. Below 52rem the margin column collapses and its contents run in. */
.ledger {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.75rem var(--gutter);
}

@media (min-width: 52rem) {
  .ledger {
    grid-template-columns: var(--col-ord) minmax(0, 1fr);
    /* Both children join one baseline sharing group, so the ordinal sits on
       the heading's baseline rather than on the row's top edge. Alignment
       set on the container, because a lone baseline aligned item falls back
       to start and silently does nothing. */
    align-items: baseline;
  }
}

/* The mono metadata voice */
.meta {
  font-family: var(--mono);
  font-size: var(--fs-micro);
  line-height: 1.5;
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* Dot leader. An empty inline box aligned on the text baseline, filled with a
   repeating dot. Used in exactly two places: section entries and contact
   rows. It is the first thing in its row allowed to give up width. */
.leader {
  flex: 1 1 1.5rem;
  min-width: 0;
  align-self: baseline;
  height: 0.5em;
  position: relative;
  top: -0.12em;
  background-image: radial-gradient(circle at 1px 100%,
                    var(--rule-strong) 1px, transparent 1.35px);
  background-size: 7px 100%;
  background-repeat: repeat-x;
  background-position: left bottom;
}


/* 5. Masthead ============================================================== */

.masthead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  /* The row gap has to clear the two 0.9rem tap target extensions below,
     or they overlap once the header wraps and the wrong link takes the tap. */
  gap: 2rem 1rem;
  flex-wrap: wrap;
  padding-block: 1.25rem 0.75rem;
  border-bottom: 1px solid var(--rule);
}

.masthead__mark { text-decoration: none; color: var(--muted); }
.masthead__mark:hover { color: var(--accent); }

.langs { display: flex; align-items: baseline; gap: 0.5rem; }

/* The language you are not on is the link, and it is underlined: which of
   the two words is clickable must not depend on colour alone. */
.langs a {
  color: var(--muted);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.35em;
}
.langs a:hover { color: var(--accent); }
.langs [aria-current="true"] { color: var(--text); text-decoration: none; }
.langs__sep { color: var(--rule-strong); }

/* A comfortable tap target without disturbing the baseline */
.langs a, .masthead__mark { position: relative; }
.langs a::after, .masthead__mark::after {
  content: "";
  position: absolute;
  inset: -0.9rem -0.35rem;
}


/* 6. Hero ================================================================== */

.hero { padding-block: clamp(2.5rem, 1.4rem + 4.4vw, 5rem) 0; }

.hero__role {
  align-self: baseline;
  margin-bottom: 0.5rem;
  color: var(--accent);
}

.hero__name {
  font-size: var(--fs-name);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.021em;
  text-wrap: balance;
  margin-inline-start: -0.035em;      /* optical: pull the D to the margin */
}

.hero__lead {
  font-size: var(--fs-lead);
  line-height: 1.44;
  max-width: 32rem;
  margin-top: 1.25rem;
  text-wrap: pretty;
}

.hero__plate { margin-top: 2rem; }

.plate__frame {
  width: 11rem;
  max-width: 55%;
  padding: 0.5rem;
  background: var(--surface);
  border: 1px solid var(--rule-strong);
}

.plate__frame img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  filter: saturate(0.96);
}

@media (prefers-color-scheme: dark) {
  .plate__frame img { filter: saturate(0.88) brightness(0.86); }
}

@media (min-width: 52rem) {
  /* Two independent grids, deliberately. The photograph is taller than the
     text block, and if it shared the text's rows it would inflate them and
     drag the rubric off the name's baseline. */
  .hero {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--gutter);
    align-items: start;
  }

  .hero__text {
    display: grid;
    grid-template-columns: var(--col-ord) minmax(0, 1fr);
    column-gap: var(--gutter);
    grid-template-areas:
      "role name"
      ".    lead";
  }

  /* Hang the rubric in the margin, on the name's own baseline. The fallback
     subtracts the name's half leading plus descender, 0.275em of its size,
     which holds across the whole clamp range. Where the browser supports
     baseline groups it does the same thing exactly, whatever monospace font
     the platform picks for the rubric. */
  .hero__role {
    grid-area: role;
    align-self: end;
    text-align: end;
    margin-bottom: calc(var(--fs-name) * 0.275);
  }
  .hero__name  { grid-area: name; }
  .hero__lead  { grid-area: lead; }

  @supports (align-self: last baseline) {
    .hero__role { align-self: last baseline; margin-bottom: 0; }
    .hero__name { align-self: last baseline; }
  }

  .hero__plate { margin-top: 0.4rem; }
  .plate__frame { max-width: none; }
}

@media (min-width: 52rem) and (max-width: 63.99rem) {
  .plate__frame { width: 9rem; }
}


/* 7. Sections and index entries ============================================ */

.section {
  margin-top: var(--rhythm);
  padding-top: 1.1rem;
  border-top: 1px solid var(--rule);
}

@media (min-width: 52rem) {
  .section__ord { text-align: end; }
}

.entry {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.7rem;
  margin-bottom: 1.5rem;
}

.entry h2 {
  flex: 0 1 auto;
  min-width: 0;
  font-size: var(--fs-h2);
  font-weight: 400;
  line-height: var(--lh-tight);
  letter-spacing: 0.01em;
}

.entry__folio {
  flex: none;
  font-family: var(--mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  color: var(--muted);
  text-decoration: none;
}
.entry__folio:hover { color: var(--accent); text-decoration: underline; }


/* 8. About ================================================================= */

.prose { max-width: var(--measure); }
.prose p + p { margin-top: 0.9em; }
.prose em { font-style: italic; }


/* 9. Areas of work ========================================================= */

.areas { max-width: 46rem; }

.area {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.15rem 0;
  padding-block: 0.85rem;
  border-top: 1px solid var(--rule);
}
.area:first-child { border-top: 0; padding-top: 0; }
.area:last-child { padding-bottom: 0; }

.area dt {
  line-height: var(--lh-tight);
  color: var(--text);
}

.area dd {
  color: var(--muted);
  font-size: var(--fs-small);
  line-height: 1.55;
  max-width: 34rem;
}

@media (min-width: 40rem) {
  .area {
    grid-template-columns: 13rem minmax(0, 1fr);
    gap: 0 var(--gutter);
    align-items: baseline;
  }
}


/* 10. Contact ============================================================== */

.contact__note { max-width: var(--measure); margin-bottom: 1.6rem; }

.channels { max-width: 30rem; }

/* The value wraps to its own line rather than being run over by the leader
   when the row cannot fit, which happens at 320px with a large default font
   size or at 200 percent zoom. */
.channel {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.7rem;
  padding-block: 0.6rem;
  border-top: 1px solid var(--rule);
}
.channel:first-child { border-top: 0; }

.channel dt {
  display: flex;
  align-items: baseline;
  gap: 0 0.7rem;
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--muted);
}

.channel dd { flex: 0 1 auto; min-width: 0; }

.channel a {
  text-decoration: underline;
  text-decoration-color: var(--rule-strong);
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
  overflow-wrap: anywhere;
}
.channel a:hover {
  color: var(--accent);
  text-decoration-color: currentColor;
}


/* 11. Colophon ============================================================= */

.colophon {
  margin-top: var(--rhythm);
  padding-block: 1.1rem 2.5rem;
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 0.7rem;
}
.colophon__sep { color: var(--rule-strong); }


/* 12. Preference queries and print ========================================= */

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

/* Every grey moves up one step. Because the roles read from --ink-*, which
   this block does not touch, each token keeps a distinct value instead of
   collapsing onto the text colour. */
@media (prefers-contrast: more) {
  :root {
    --muted: var(--text);
    --rule: var(--ink-30);
    --rule-strong: var(--ink-70);
  }
  .channel a { text-decoration-color: currentColor; }
}

@media print {
  :root {
    --bg: #FFF; --surface: #FFF; --text: #000;
    --ink-70: #333; --ink-30: #888; --ink-15: #BBB;
    --accent: #000;
  }
  .masthead, .skip, .entry__folio, .leader { display: none; }
  .section { break-inside: avoid; }
  .channel a::after { content: " (" attr(href) ")"; font-family: var(--mono); font-size: 0.75em; }
  .channel a[href^="mailto:"]::after { content: ""; }
}
