/* ---------------------------------------------------------------
   Davide Veronese — personal page
   Zero JavaScript. Two decorative layers, both static or
   composited-transform only, so nothing repaints after first paint.
   --------------------------------------------------------------- */

@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 300 700;          /* variable font: one file covers the range */
  font-display: swap;
  src: url("assets/fonts/SpaceGrotesk-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
    U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
    U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("assets/fonts/SpaceGrotesk-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
    U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

:root {
  color-scheme: dark;

  --night: #020a0c;
  --ink: #e8f3f3;      /* headings, emphasis            */
  --body: #bed1d1;     /* running text — 11.6:1 on night */
  --quiet: #b4c8ca;    /* labels, meta - 5.0:1 even under the brightest orb */
  --cyan: #7ae6ef;
  --cyan-lift: #c4fbff;
  --line: rgba(199, 229, 231, 0.13);

  --mx: 50%;
  --my: 36%;

  --col: 620px;        /* ~72 characters at 15px          */
  --gap: 16px;        /* vertical rhythm between sections */
}

* {
  box-sizing: border-box;
}

html {
  min-height: 100%;
  background: var(--night);
}

body {
  min-height: 100vh;
  margin: 0;
  /* Static field: one warm centre, darkened at the edges.
     Replaces the old JS-driven vignette layer entirely. */
  background: var(--night);
  color: var(--body);
  font-family: "Space Grotesk", "Avenir Next", Avenir, system-ui, sans-serif;
  font-size: 15px;
  font-weight: 400;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* --- Grain -----------------------------------------------------
   The one texture that makes flat colour feel like a surface.
   Well under half the previous opacity, and soft-light rather than
   overlay so it settles into the field instead of sitting on it. */
body::after {
  position: fixed;
  z-index: 3;
  inset: 0;
  pointer-events: none;
  content: "";
  opacity: 0.05;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .06 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}

/* --- Aurora field ------------------------------------------------
   Five large, overlapping colour fields plus a slow spectrum ring.
   They are deliberately bigger than the viewport and set to blend
   with screen, so there are no dead patches between them - the page
   sits inside one continuous wash rather than on a dark ground with
   tints on it.

   Chroma is high and luminance is kept low: saturated colour at low
   brightness is what lets the wash read as vivid while light text
   still clears contrast over it.

   Every layer animates transform only, each carrying a static blur
   the browser renders once and then just moves. No repaints. */

.field {
  position: fixed;
  z-index: 1;
  inset: -60px;              /* bleed, so pointer parallax never shows an edge */
  overflow: hidden;
  pointer-events: none;
  will-change: transform;
}

.orb,
.ring {
  position: absolute;
  display: block;
  border-radius: 50%;
  mix-blend-mode: screen;
}

/* Teal - upper left */
.orb-1 {
  top: -40%;
  left: -28%;
  width: clamp(620px, 76vw, 1320px);
  aspect-ratio: 1.2;
  opacity: 0.225;
  filter: blur(96px);
  background: radial-gradient(
    circle at 40% 38%,
    rgba(34, 214, 206, 0.8) 0%,
    rgba(22, 158, 186, 0.44) 40%,
    rgba(16, 96, 140, 0.16) 64%,
    transparent 78%
  );
  animation: orb1 29s ease-in-out infinite alternate;
}

/* Electric blue - upper right, overlaps the teal across the top */
.orb-2 {
  top: -34%;
  right: -22%;
  width: clamp(580px, 72vw, 1240px);
  aspect-ratio: 1.1;
  opacity: 0.23;
  filter: blur(100px);
  background: radial-gradient(
    circle at 56% 46%,
    rgba(84, 128, 255, 0.76) 0%,
    rgba(66, 92, 224, 0.4) 42%,
    transparent 74%
  );
  animation: orb2 37s ease-in-out infinite alternate;
}

/* Violet - right flank, carries the middle */
.orb-3 {
  top: 18%;
  right: -26%;
  width: clamp(560px, 68vw, 1180px);
  aspect-ratio: 1.25;
  opacity: 0.23;
  filter: blur(102px);
  background: radial-gradient(
    circle at 52% 50%,
    rgba(172, 96, 255, 0.78) 0%,
    rgba(132, 72, 218, 0.4) 42%,
    transparent 75%
  );
  animation: orb3 41s ease-in-out infinite alternate;
}

/* Magenta - lower right */
.orb-4 {
  right: -16%;
  bottom: -26%;
  width: clamp(520px, 64vw, 1100px);
  aspect-ratio: 1.15;
  opacity: 0.2;
  filter: blur(98px);
  background: radial-gradient(
    circle at 50% 50%,
    rgba(255, 104, 176, 0.66) 0%,
    rgba(206, 74, 158, 0.34) 44%,
    transparent 75%
  );
  animation: orb4 47s ease-in-out infinite alternate;
}

/* Amber - lower left, the warm corner that keeps it from going cold */
.orb-5 {
  bottom: -28%;
  left: -20%;
  width: clamp(540px, 66vw, 1140px);
  aspect-ratio: 1.3;
  opacity: 0.165;
  filter: blur(104px);
  background: radial-gradient(
    circle at 48% 52%,
    rgba(255, 168, 78, 0.56) 0%,
    rgba(214, 118, 72, 0.3) 44%,
    transparent 76%
  );
  animation: orb5 53s ease-in-out infinite alternate;
}

/* Spectrum ring - four minutes per revolution, blurred past the point
   of being a rainbow. It reads as the wash slowly changing its mind. */
.ring {
  top: 46%;
  left: 50%;
  width: clamp(760px, 96vw, 1760px);
  aspect-ratio: 1;
  opacity: 0.09;
  filter: blur(124px) saturate(170%);
  background: conic-gradient(
    from 0deg,
    rgba(34, 214, 206, 0.9),
    rgba(84, 128, 255, 0.85),
    rgba(172, 96, 255, 0.9),
    rgba(255, 104, 176, 0.72),
    rgba(255, 168, 78, 0.6),
    rgba(86, 240, 190, 0.8),
    rgba(34, 214, 206, 0.9)
  );
  animation: ring 120s linear infinite;
}

@keyframes orb1 {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(9vw, 5vh, 0) scale(1.14); }
}

@keyframes orb2 {
  from { transform: translate3d(0, 0, 0) scale(1.08); }
  to   { transform: translate3d(-7vw, 7vh, 0) scale(0.94); }
}

@keyframes orb3 {
  from { transform: translate3d(0, 0, 0) scale(0.96); }
  to   { transform: translate3d(8vw, -6vh, 0) scale(1.16); }
}

@keyframes orb4 {
  from { transform: translate3d(0, 0, 0) scale(1.1); }
  to   { transform: translate3d(-6vw, -8vh, 0) scale(0.92); }
}

@keyframes orb5 {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(7vw, -5vh, 0) scale(1.12); }
}

@keyframes ring {
  from { transform: translate(-50%, -50%) rotate(0deg); }
  to   { transform: translate(-50%, -50%) rotate(360deg); }
}

/* --- Cursor tone ------------------------------------------------
   Not a light that follows the pointer - the pointer re-anchors the
   origin of a conic hue wheel, so every pixel's colour depends on its
   angle to the cursor and the whole field redistributes as you move.
   A radial tint rides along at the same origin.

   Deliberately unblurred: these two repaint as --mx/--my change, and
   a blur would make that expensive. The blurred ambient orbs never
   repaint - they only ever move. */

.slicks {
  position: fixed;
  z-index: 2;
  inset: 0;
  pointer-events: none;
}

.slick {
  position: absolute;
  inset: 0;
  mix-blend-mode: screen;
}

.slick-a {
  opacity: var(--slick-a, 0.07);
  background: conic-gradient(
    from 0deg at var(--mx) var(--my),
    rgba(20, 182, 193, 0.9),
    rgba(91, 227, 255, 0.9),
    rgba(177, 91, 217, 0.85),
    rgba(255, 106, 122, 0.6),
    rgba(245, 196, 94, 0.6),
    rgba(182, 255, 206, 0.75),
    rgba(20, 182, 193, 0.9)
  );
}

.slick-b {
  opacity: var(--slick-b, 0.09);
  background: radial-gradient(
    circle at var(--mx) var(--my),
    rgba(91, 227, 255, 0.45) 0%,
    rgba(177, 91, 217, 0.3) 18%,
    rgba(20, 182, 193, 0.18) 36%,
    rgba(0, 0, 0, 0) 62%
  );
}

/* Touch devices never match (pointer: fine), so the cursor-tone script
   returns early and --slick-a/-b are never set - the wash sits at its
   dim resting fallback forever. There is no pointer to follow on a
   phone, so raise the static values instead, to about where the desktop
   field sits mid-gesture. The origin stays at the CSS default 50%/36%. */
@media (pointer: coarse) {
  .slick-a {
    opacity: 0.16;
  }

  .slick-b {
    opacity: 0.22;
  }
}

/* --- Shell ------------------------------------------------------ */

main {
  position: relative;
  z-index: 4;
  width: min(100% - 44px, var(--col));
  margin: 0 auto;
  padding: 60px 0 52px;
}

/* --- Masthead ---------------------------------------------------
   Name and place share one baseline over a hairline. This is the
   whole header: no large display type, no icon row. */

.masthead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

h1 {
  margin: 0;
  color: var(--ink);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  line-height: 1.4;
  text-transform: uppercase;
}

.handles {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  justify-content: flex-end;
}

/* Handles, not labels. The old bare "X" sat top-right in uppercase and
   read as a close button, so each link now carries its brand mark and
   the actual handle. Mixed case and near-normal tracking separate these
   from the uppercase section labels: they are names, not headings. */
.handles a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--quiet);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-decoration: none;
  white-space: nowrap;
  transition: color 160ms ease;
}

.handles .mark {
  width: 11px;
  height: 11px;
  flex: none;
  fill: currentColor;
  opacity: 0.8;
  transition: opacity 160ms ease;
}

.handles a:hover .mark {
  opacity: 1;
}

.handles a:hover {
  color: var(--cyan-lift);
  text-decoration: none;
  text-shadow: 0 0 14px rgba(122, 230, 239, 0.45);
}

/* --- Bio -------------------------------------------------------- */

.bio {
  margin: 22px 0 0;
  padding-left: 17px;
  list-style: disc;
}

.bio li + li {
  margin-top: 7px;
}

.bio li::marker {
  color: var(--quiet);
  font-size: 0.7em;
}

/* --- Sections --------------------------------------------------- */

section {
  margin-top: var(--gap);
}

h2 {
  margin: 0 0 11px;
  color: var(--quiet);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.18em;
  line-height: 1.4;
  text-transform: uppercase;
}

p {
  margin: 0;
}

/* Hairline-separated rows: the only geometry on the page. */

.questions {
  margin: 0;
  padding-left: 17px;
  list-style: disc;
}

.questions li + li {
  margin-top: 7px;
}

.questions li::marker {
  color: var(--quiet);
  font-size: 0.7em;
}

/* --- Links ------------------------------------------------------ */

a {
  color: var(--cyan);
  text-decoration: underline;
  text-decoration-color: rgba(122, 230, 239, 0.28);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color 160ms ease, text-decoration-color 160ms ease;
}

a:hover {
  color: var(--cyan-lift);
  text-decoration-color: currentColor;
  text-shadow: 0 0 16px rgba(122, 230, 239, 0.4);
}

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

.out::after {
  content: "\2197";          /* ↗ */
  margin-left: 3px;
  font-size: 0.86em;
  opacity: 0.6;
}

/* --- Ordered Pairs block (variant B only) ----------------------- */

.op {
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: linear-gradient(
    160deg,
    rgba(198, 240, 243, 0.05),
    rgba(5, 26, 29, 0.2)
  );
}

.op-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
}

.op-name {
  margin: 0;
  color: var(--ink);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.18em;
  line-height: 1.4;
  text-transform: uppercase;
}

.op-posts {
  margin-top: 13px;
  padding-top: 3px;
}

.op-posts li {
  display: block;
}

.op-posts li + li {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
}

.op-posts {
  margin-left: 0;
  padding-left: 0;
  list-style: none;
}

/* Post titles read as text, not as links. Three cyan lines stacked in a
   row was all accent and no hierarchy - the box already announces what
   it is, so the titles can sit quiet and Subscribe carries the one
   accent. The link affordance arrives on hover. */

.op-posts a {
  color: var(--ink);
  text-decoration-color: transparent;
}

.op-posts a:hover {
  color: var(--cyan-lift);
  text-decoration-color: rgba(122, 230, 239, 0.45);
  text-shadow: none;
}

.op-head a {
  color: var(--cyan);
  font-size: 13px;
  letter-spacing: 0.02em;
}

/* --- Folds -------------------------------------------------------
   Each section collapses. The summary carries exactly the label
   styling the h2 had, plus a CSS-drawn triangle that rotates - a
   triangle reads as open/closed at 10px, which the old diamond
   never did. */

summary {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin: 0;
  padding: 10px 0;          /* 14px of text needs a real hit area */
  color: var(--quiet);
  cursor: pointer;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.18em;
  line-height: 1.4;
  list-style: none;
  text-transform: uppercase;
  user-select: none;
  transition: color 160ms ease;
}

summary::-webkit-details-marker {
  display: none;
}

summary::before {
  width: 0;
  height: 0;
  border-top: 3.5px solid transparent;
  border-bottom: 3.5px solid transparent;
  border-left: 5px solid currentColor;
  content: "";
  opacity: 0.75;
  transition: transform 180ms ease;
}

summary:hover {
  color: var(--ink);
}

summary:focus-visible {
  outline: 1px solid var(--cyan);
  outline-offset: 4px;
  border-radius: 1px;
}

details[open] > summary::before {
  transform: rotate(90deg);
}

details[open] > summary {
  margin-bottom: 2px;
}

/* --- Paintings plate --------------------------------------------
   Stands in for the embed. Sized and lit like a panel rather than a
   link, so the section still reads as a gallery even though the
   works live in Ente. Picks up the aurora behind it on hover. */

.plate {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 20px 22px;
  border: 1px solid rgba(199, 229, 231, 0.16);
  border-radius: 12px;
  background: linear-gradient(
    150deg,
    rgba(198, 240, 243, 0.06),
    rgba(5, 26, 29, 0.28)
  );
  box-shadow: inset 0 1px rgba(255, 255, 255, 0.04);
  text-decoration: none;
  transition: border-color 220ms ease, background 220ms ease, transform 220ms ease;
}

.plate:hover {
  border-color: rgba(122, 230, 239, 0.4);
  background: linear-gradient(
    150deg,
    rgba(198, 240, 243, 0.1),
    rgba(5, 26, 29, 0.24)
  );
  transform: translateY(-1px);
  text-decoration: none;
}

.plate-title {
  color: var(--cyan);
  font-size: 15px;
}

.plate:hover .plate-title {
  color: var(--cyan-lift);
}

.plate-meta {
  color: var(--quiet);
  font-size: 12px;
}

.plate-arrow {
  display: inline-block;
  transition: transform 220ms ease;
}

.plate:hover .plate-arrow {
  transform: translate(2px, -2px);
}

/* --- Narrow ----------------------------------------------------- */

@media (max-width: 560px) {
  summary {
    padding: 14px 0;        /* ~42px row on touch */
  }

  body {
    min-height: 100svh;
    font-size: 15px;
  }

  main {
    width: min(100% - 32px, var(--col));
    padding: 54px 0 48px;
  }

  /* Keep the name and the handles on one band. The handles stack
     against the right edge instead of dropping under the name, and
     the base baseline alignment puts the first handle on the same
     baseline as the name. */
  .masthead {
    gap: 12px;
  }

  .handles {
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
  }

  .op {
    padding: 14px 15px;
  }

  .op-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }
}

/* --- Reduced motion --------------------------------------------- */

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

  .slicks {
    display: none;
  }
}
