@charset "utf-8";

/* ==========================================================================
   Chiara Falzi - Marketing Portfolio
   Palette and type derived from the Canva draft (v2, bordeaux / cream)

   AFFORDANCE RULE, applied throughout:
     rounded + filled  = you can click it
     square / hairline = you read it
   Nothing static is ever shaped like a button.
   ========================================================================== */

:root {
  --bordeaux: #550000;
  --bordeaux-soft: #7d2020;
  --bordeaux-ink: #3d0000;
  --cream: #fff5ec;
  --cream-deep: #f7e9db;
  --sand: #e8d5c4;
  --sand-deep: #eddac0;
  --brown: #4f1e0c;
  --gold: #c9a24a;
  --white: #ffffff;

  --font-display: "Playfair Display", Georgia, "Times New Roman", serif;
  --font-body: "Lora", Georgia, "Times New Roman", serif;
  --font-script: "Ms Madi", "Brush Script MT", cursive;

  --wrap: 1120px;
  --gutter: clamp(1.25rem, 5vw, 3.5rem);
  --section-y: clamp(3.75rem, 9vw, 7rem);
  --nav-h: 58px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: var(--nav-h);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--cream);
  color: var(--bordeaux-ink);
  font-family: var(--font-body);
  font-size: clamp(1rem, 0.96rem + 0.18vw, 1.0625rem);
  line-height: 1.72;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip-link {
  position: absolute; left: 50%; top: 0;
  transform: translate(-50%, -120%);
  z-index: 100;
  padding: 0.6rem 1.2rem;
  background: var(--cream); color: var(--bordeaux);
  font-size: 0.8rem; text-decoration: none;
  transition: transform 0.2s var(--ease);
}
.skip-link:focus { transform: translate(-50%, 0); }

/* --- Type primitives ---------------------------------------------------- */

.section-title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.25rem, 7.5vw, 4.75rem);
  line-height: 1.02;
  text-transform: uppercase;
  margin: 0 0 clamp(1.5rem, 4vw, 2.5rem);
  text-align: center;
  color: var(--bordeaux);
}

/* Letterspaced small caps. Never bordered, never rounded: it is a label. */
.label {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin: 0 0 0.5rem;
  color: var(--bordeaux-soft);
}

/* --- The only two button shapes on the page ----------------------------- */

.btn {
  display: inline-block;
  border: 0;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  padding: 0.75rem 1.75rem;
  transition: transform 0.25s var(--ease), background 0.25s var(--ease),
              color 0.25s var(--ease);
}

.btn--solid { background: var(--cream); color: var(--bordeaux); }
.btn--ghost { background: transparent; color: var(--cream); box-shadow: inset 0 0 0 1px currentColor; }

.btn:hover, .btn:focus-visible { transform: translateY(-2px); }
.btn--ghost:hover, .btn--ghost:focus-visible { background: var(--cream); color: var(--bordeaux); }

/* --- Sections ----------------------------------------------------------- */

.section { padding-block: var(--section-y); }
.section--cream { background: var(--cream); }

/* Shared pinned viewport used by the bag and the work section. */
.pin {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
}

/* --- Reading progress --------------------------------------------------- */

.readbar {
  position: fixed;
  inset: 0 0 auto 0;
  height: 2px;
  z-index: 60;
  background: transparent;
  pointer-events: none;
}

.readbar::after {
  content: "";
  display: block;
  height: 100%;
  width: 100%;
  background: var(--gold);
  transform: scaleX(var(--read, 0));
  transform-origin: 0 50%;
}

/* --- Navigation --------------------------------------------------------- */

.nav {
  position: sticky; top: 0; z-index: 50;
  background: var(--bordeaux);
  border-bottom: 1px solid rgba(255, 245, 236, 0.16);
}

.nav__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; min-height: var(--nav-h);
}

.nav__list {
  display: flex; align-items: center;
  gap: clamp(0.85rem, 3vw, 2.25rem);
  list-style: none; margin: 0; padding: 0;
}

.nav__link {
  display: inline-block; padding: 0.35rem 0;
  color: var(--cream);
  font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.17em; text-transform: uppercase; text-decoration: none;
  border-bottom: 1.5px solid transparent;
  transition: border-color 0.25s var(--ease);
}

.nav__link:hover, .nav__link:focus-visible,
.nav__link[aria-current="true"] { border-bottom-color: var(--cream); }

.nav__cv { padding: 0.45rem 1.1rem; font-size: 0.64rem; }

@media (max-width: 780px) {
  .nav__list {
    flex: 1; gap: 1.1rem;
    overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none;
    padding-block: 0.5rem;
  }
  .nav__list::-webkit-scrollbar { display: none; }
  .nav__link { font-size: 0.62rem; letter-spacing: 0.08em; white-space: nowrap; }
  .nav__cv { display: none; }
}

/* --- Hero --------------------------------------------------------------- */

.hero {
  position: relative;
  background: var(--cream);
  padding-top: clamp(1.5rem, 4vw, 3rem);
  overflow: hidden;
}

/* minmax(0, 1fr) keeps the column the width of the container. Without it the
   unbreakable word MARKETING sizes the implicit column to its own min-content,
   the track grows past the wrapper, and everything centred inside it drifts
   off the page axis. */
.hero__stage {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
}
.hero__word, .hero__photo, .hero__script { grid-area: 1 / 1; }

.hero__word {
  font-family: var(--font-display); font-weight: 900;
  font-size: min(12.2vw, 11.5rem);
  line-height: 0.9; letter-spacing: -0.02em;
  text-transform: uppercase; text-align: center;
  color: var(--bordeaux);
  margin: 0; z-index: 1; align-self: start;
  animation: heroWord 1.1s var(--ease-out) both;
}

.hero__photo {
  display: block; z-index: 2;
  height: clamp(290px, 52vh, 560px);
  align-self: start;
  margin-top: clamp(1.75rem, 5.5vw, 4rem);
  filter: drop-shadow(0 22px 38px rgba(85, 0, 0, 0.2));
  animation: heroPhoto 1.3s 0.15s var(--ease-out) both;
}

.hero__photo img {
  height: 100%; width: auto;
  -webkit-mask-image: linear-gradient(to bottom, #000 78%, transparent 98%);
  mask-image: linear-gradient(to bottom, #000 78%, transparent 98%);
}

.hero__script {
  z-index: 3; align-self: end; margin: 0;
  color: var(--bordeaux);
  font-family: var(--font-script);
  font-size: clamp(2.75rem, 10.5vw, 7rem);
  line-height: 1; pointer-events: none;
  transform: translateY(0.1em);
  animation: heroScript 1.2s 0.5s var(--ease-out) both;
}

@keyframes heroWord { from { opacity: 0; transform: translateY(0.12em) scale(1.04); } }
@keyframes heroPhoto { from { opacity: 0; transform: translateY(30px); } }
@keyframes heroScript { from { opacity: 0; transform: translateY(0.4em) rotate(-3deg); } }

.hero__meta {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 1rem;
  margin-top: clamp(1.5rem, 3.5vw, 2.25rem);
  padding-bottom: clamp(1.75rem, 4vw, 2.75rem);
}

.hero__meta .label { margin: 0; color: var(--bordeaux); }

.hero__scrollcue { position: relative; padding-bottom: 1.6rem; }
.hero__scrollcue::after {
  content: ""; position: absolute; left: 50%; bottom: 0;
  width: 1px; height: 1.1rem; background: var(--bordeaux);
  animation: cue 1.8s var(--ease) infinite;
}
@keyframes cue {
  0% { transform: scaleY(0); transform-origin: 0 0; }
  45% { transform: scaleY(1); transform-origin: 0 0; }
  55% { transform: scaleY(1); transform-origin: 0 100%; }
  100% { transform: scaleY(0); transform-origin: 0 100%; }
}

@media (max-width: 560px) { .hero__scrollcue { display: none; } }

/* --- About: pinned keyword panel, scrolling story ----------------------- */

.about {
  background: var(--bordeaux);
  color: var(--cream);
  padding-block: clamp(3rem, 8vw, 6rem);
}

.about__title {
  margin: 0 0 clamp(2rem, 6vw, 4rem);
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.75rem, 11vw, 8rem);
  line-height: 0.86;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--cream);
}

/* "me" drops to a second line in the script face, echoing the cover. */
.about__title span {
  display: block;
  font-family: var(--font-script);
  font-size: 0.78em;
  line-height: 0.95;
  text-transform: none;
  letter-spacing: 0;
  padding-left: 0.12em;
}

.about__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 5vw, 4.5rem);
  align-items: start;
}

.about__sticky {
  position: sticky;
  top: calc(var(--nav-h) + 8vh);
  display: flex;
  gap: 1.25rem;
}

/* The panel holds the photo, a scrim, and the keyword on top of both. */
.about__panel {
  position: relative;
  flex: 1;
  min-width: 0;
  aspect-ratio: 4 / 5;
  max-height: 64vh;
  display: flex;
  align-items: flex-end;
  padding: clamp(1rem, 2.5vw, 1.75rem);
  overflow: hidden;
  background: var(--bordeaux-ink);
}

.about__photos { position: absolute; inset: 0; }

/* The image is set inline on the element (see index.html). With no photo the
   panel stays a plain bordeaux block and the section still reads. */
.about__photo {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0;
  transform: scale(1.06);
  transition: opacity 0.8s var(--ease-out), transform 1.6s var(--ease-out);
}

.about__photo.is-on { opacity: 1; transform: none; }

.about__panel::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top,
    rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0.42) 24%, rgba(0, 0, 0, 0) 52%);
}

.about__word {
  position: relative;
  z-index: 2;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 900;
  font-style: italic;
  font-size: clamp(1.5rem, 3.4vw, 2.9rem);
  line-height: 1.02;
  letter-spacing: -0.01em;
  color: var(--cream);
  opacity: 0;
  transform: translateY(0.4em);
  transition: opacity 0.5s var(--ease-out), transform 0.6s var(--ease-out);
}

/* All four occupy the same corner; only the active one is visible. */
.about__word + .about__word { position: absolute; left: clamp(1rem, 2.5vw, 1.75rem);
                              bottom: clamp(1rem, 2.5vw, 1.75rem);
                              right: clamp(1rem, 2.5vw, 1.75rem); }

.about__word.is-on { opacity: 1; transform: none; }

.about__rail {
  flex-shrink: 0;
  width: 2px;
  align-self: stretch;
  background: rgba(255, 245, 236, 0.2);
  position: relative;
  order: -1;
}

.about__railfill {
  position: absolute; inset: 0 0 auto 0;
  height: 100%;
  background: var(--gold);
  transform: scaleY(var(--about-p, 0));
  transform-origin: 50% 0;
  transition: transform 0.5s var(--ease);
}

.about__flow { padding-block: clamp(1rem, 5vh, 4rem); }

.about__step {
  padding-block: clamp(2.5rem, 10vh, 6.5rem);
  opacity: 0.3;
  transition: opacity 0.5s var(--ease);
}

.about__step.is-on { opacity: 1; }
.about__step:first-of-type { padding-top: 0; }

.about__year {
  margin: 0 0 0.75rem;
  font-family: var(--font-body);
  font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--gold);
}

.about__text {
  margin: 0;
  font-size: clamp(1.05rem, 1.9vw, 1.3rem);
  line-height: 1.6;
}

.about__text strong { color: var(--white); font-weight: 700; }

/* Soft snap: each block settles centred, without ever trapping the scroll.
   Only above the breakpoint, and never while motion is reduced. */
@media (min-width: 861px) and (prefers-reduced-motion: no-preference) {
  html { scroll-snap-type: y proximity; }
  .about__step { scroll-snap-align: center; }
}

@media (max-width: 860px) {
  .about__grid { grid-template-columns: 1fr; gap: 0; }
  .about__sticky {
    top: var(--nav-h);
    padding-block: 0.75rem;
    background: var(--bordeaux);
    z-index: 5;
    box-shadow: 0 14px 20px -14px rgba(0, 0, 0, 0.6);
  }
  .about__panel {
    aspect-ratio: auto;
    max-height: none;
    min-height: 3.4rem;
    align-items: center;
    padding: 0.65rem 1rem;
    background: none;
  }
  .about__panel::after { display: none; }
  .about__photos { display: none; }
  .about__word { font-size: clamp(1.5rem, 7vw, 2.25rem); }
  .about__word + .about__word { left: 1rem; right: 1rem; bottom: auto; top: 50%;
                                transform: translateY(-50%) translateY(0.3em); }
  .about__word + .about__word.is-on { transform: translateY(-50%); }
  .about__rail { align-self: stretch; }
  .about__step { opacity: 1; padding-block: clamp(1.75rem, 5vh, 2.5rem); }
}

/* --- What's in my bag ---------------------------------------------------
   A single pinned section. --p scrubs the spill; after that the section
   switches to discrete steps and one object at a time is pulled out of the
   group into the spotlight. The objects are never removed and never
   re-created, which is what makes the two halves read as one thing.
   ---------------------------------------------------------------------- */

.bag { height: 700vh; background: var(--cream); }

.bag__pin { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; }

/* The world darkens around the objects instead of cutting to a new section. */
/* No colour change at all: the section is cream from the bag emptying to
   the last object, so the two halves are one continuous space. */

.bag__stage { position: relative; height: 100%; z-index: 1; }

.bag__title {
  position: absolute;
  left: 50%;
  top: 12%;
  transform: translateX(-50%);
  width: 100%;
  margin: 0;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.1rem, 7.5vw, 5.5rem);
  line-height: 0.95;
  letter-spacing: -0.015em;
  text-transform: uppercase;
  color: var(--bordeaux);
  transition: opacity 0.6s var(--ease), transform 0.8s var(--ease-out);
  z-index: 3;
}

.bag__title em {
  display: block;
  font-family: var(--font-script);
  font-style: normal;
  font-size: 1.2em;
  line-height: 0.95;
  text-transform: none;
  letter-spacing: 0;
}

.bag.is-explaining .bag__title {
  opacity: 0;
  transform: translateX(-50%) translateY(-2rem);
}

.bag__tote {
  position: absolute;
  left: 50%;
  top: 58%;
  width: min(52vw, 400px);
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 30px 50px rgba(85, 0, 0, 0.2));
  transition: opacity 0.7s var(--ease), transform 0.9s var(--ease-out);
  z-index: 1;
}

.bag.is-explaining .bag__tote {
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.82);
}

/* --- The six objects ----------------------------------------------------
   Position, scale and opacity all come from main.js, one value per frame:
   the objects travel in depth and CSS cannot express the piecewise easing.
   ---------------------------------------------------------------------- */

.bag__objects { position: absolute; inset: 0; margin: 0; padding: 0; list-style: none; z-index: 2; }

.bag__obj {
  position: absolute;
  left: 50%;
  top: 52%;
  opacity: var(--op, 0);
  transform:
    translate(-50%, -50%)
    translate(var(--tx, 0px), var(--ty, 0px))
    rotate(var(--rot, 0deg))
    scale(var(--sc, 0.3));
}

/* Object photos. Each carries a --sz multiplier so a long pen and a wide
   planner sit at believable relative sizes instead of one flat height. */
.obj {
  /* Laid out at the size the object reaches when it arrives, so the browser
     rasterises it once at full resolution and the scale only ever shrinks it.
     Sizing it small and scaling up produced a blurry upscaled texture. */
  --u: clamp(210px, 26vw, 330px);
  display: block;
  width: auto;
  height: calc(var(--sz, 1) * var(--u));
  max-width: calc(var(--sz, 1) * var(--u) * 1.7);
  object-fit: contain;
  filter: drop-shadow(0 14px 24px rgba(85, 0, 0, 0.22));
}

.bag__obj:nth-child(1) { --sz: 0.85; }   /* rossetto  */
.bag__obj:nth-child(2) { --sz: 1;    }   /* telefono  */
.bag__obj:nth-child(3) { --sz: 1.15; }   /* penna     */
.bag__obj:nth-child(4) { --sz: 0.8;  }   /* agenda    */
.bag__obj:nth-child(5) { --sz: 0.95; }   /* passaporto*/
.bag__obj:nth-child(6) { --sz: 0.9;  }   /* scontrino */

/* --- The captions -------------------------------------------------------
   The layer fills the pin; each caption places itself on the half opposite
   its object, alternating down the sequence.
   ---------------------------------------------------------------------- */

.bag__texts {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  z-index: 5;
}

.bag__text {
  position: absolute;
  top: 50%;
  width: min(50vw, 560px);
  opacity: 0;
  transform: translateY(-50%) translateY(1.25rem);
  transition: opacity 0.45s var(--ease-out), transform 0.6s var(--ease-out);
  pointer-events: none;
}

/* Object on the left, caption on the right - and the other way round. */
.bag__text:nth-child(odd)  { right: clamp(1.5rem, 13vw, 13rem); }
.bag__text:nth-child(even) { left: clamp(1.5rem, 13vw, 13rem); }

.bag__text.is-on { opacity: 1; transform: translateY(-50%); }

.bag__n { margin: 0 0 0.5rem; font-size: 0.7rem; letter-spacing: 0.2em; color: var(--bordeaux-soft); }

.bag__name {
  margin: 0 0 0.65rem;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.7rem, 4vw, 3.2rem);
  line-height: 1.04;
  text-transform: uppercase;
  overflow-wrap: break-word;
  hyphens: manual;
  color: var(--bordeaux);
}

.bag__note {
  margin: 0;
  font-size: clamp(1.05rem, 1.9vw, 1.35rem);
  line-height: 1.55;
  color: var(--bordeaux-ink);
}

@media (max-width: 820px) {
  /* Stacked, and still alternating: object above then below, caption opposite. */
  .bag__text:nth-child(odd),
  .bag__text:nth-child(even) {
    left: 0;
    right: auto;
    width: 100%;
    padding-inline: var(--gutter);
    text-align: center;
  }
  .bag__text:nth-child(odd)  { top: auto; bottom: 9vh; transform: translateY(1.25rem); }
  .bag__text:nth-child(even) { top: 9vh; bottom: auto; transform: translateY(-1.25rem); }
  .bag__text:nth-child(odd).is-on,
  .bag__text:nth-child(even).is-on { transform: none; }
}

/* --- Work: four cards, each sliding up over the one before ---------------

   Vertical, not a horizontal ribbon. The ribbon fought the content: the words
   are the subject here, and a ribbon is always carrying them away. Three
   mechanics, at three scales -

   the section   the four chapters stack, each sliding up over the previous
   the chapter   the pictures hold still on one side while the text scrolls
   the element   the list composes itself, item by item, as you reach it
   -------------------------------------------------------------------------- */

/* The stage is bordeaux: it keeps the break from the cream bag section above,
   and it is what lets the cards read as cards - cream paper on a dark ground. */
.work {
  background: var(--bordeaux);
  color: var(--cream);
  position: relative;
  --ruler-h: 8.6rem;
}

/* The bag section above ends cream and PopWave begins cream, so without a
   heading the two run into each other as one undivided stretch. */
/* Inside the first card, on the red. It is the top of the section and the
   line that separates it from the bag above at the same time. */
/* The stage: the folder sits in the middle of the screen with the four cards
   out of it, each showing a preview. The depth is behind a click rather than
   behind more scrolling - which is what keeps this from being a second
   version of the bag. */
.work__stage {
  min-height: calc(100svh - var(--nav-h));
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: clamp(1.25rem, 3.5vh, 2.5rem);
  padding: clamp(2rem, 5vh, 3.5rem) var(--gutter) clamp(2rem, 5vh, 3.5rem);
  text-align: center;
}

.work__headtext { max-width: 42rem; }

/* --- The folder ---------------------------------------------------------

   A portfolio is literally a case for loose sheets, so the four projects
   come out of one as cards. It is only the way in: the section below is not
   a second locked sequence, because the bag already is one and two of them
   in a row read as a repeat.
   ------------------------------------------------------------------------ */

.wallet {
  position: relative;
  /* Una misura sola, riusata sotto: la foto e' alta il 55% della sua
     larghezza, e le tessere si agganciano a quella proporzione. */
  /* Il terzo termine e' quello che conta su uno schermo basso: il
     portafoglio piu' il ventaglio sopra non entrano in una finestra corta,
     e senza questo la scena sfora e il portafoglio resta tagliato. */
  --w: min(90vw, 30rem, 56vh);
  width: var(--w);
  margin-inline: auto;
  /* The fan is positioned out of flow, so without this the layout would
     reserve only the height of the folder itself and the cards would climb
     over the title above. The padding is the fan's room, inside the box. */
  /* In rem, not vh: the fan is measured in rem, so a viewport-based padding
     came up short on a short screen and the cards climbed over the title. */
  /* Il ventaglio contiene testo, che non scala con --w: piu' il portafoglio
     e' piccolo, piu' le tessere sono alte in proporzione. Da qui il margine
     generoso, tarato sul caso peggiore. */
  padding-block-start: calc(var(--w) * 0.62 + 5rem);
}

.wallet__art {
  display: block;
  width: 100%;
  position: relative;
  /* Davanti a ogni tessera: e' quello che permette loro di stare dentro il
     portafoglio prima di uscirne. */
  z-index: 10;
  filter: drop-shadow(0 20px 30px rgba(0, 0, 0, 0.42));
}

/* A photograph, cut out the way the tote in the bag section is: the two are
   the same brand and the same language, so the drawn version was always
   going to sit oddly next to it. */
.wallet__art img {
  display: block;
  width: 100%;
  height: auto;
}



/* The cards sit behind the folder and rise out of its mouth. --f is the fan,
   0 closed and 1 open, written by main.js from how far the section has come
   up the screen. */
.wallet__cards {
  position: absolute;
  /* Anchored to the folder's mouth, a fixed distance up from its bottom
     edge. A percentage moved with the box, and the box now carries the fan's
     own padding, so the cards drifted further up the taller it got. */
  /* Anchored to the photograph's own top edge so the cards tuck behind it.
     Derived from the wallet's width rather than fixed: on a phone the
     picture is smaller, and a fixed number left the cards floating above
     it there. */
  inset: auto 0 calc(var(--w) * 0.387) 0;
  list-style: none; margin: 0; padding: 0;
  z-index: 1;
  height: 0;
}

.wallet__slot {
  position: absolute;
  left: 50%; bottom: 0;
  width: calc(var(--w) * 0.367);
  margin-left: calc(var(--w) * -0.1835);
}

.card {
  display: block; width: 100%;
  margin: 0; padding: 0.85rem 0.9rem 0.95rem;
  text-align: left;
  font: inherit; color: inherit;
  background: var(--cream);
  color: var(--bordeaux-ink);
  border: 1px solid color-mix(in srgb, var(--bordeaux-ink) 22%, transparent);
  border-radius: 4px;
  box-shadow: 0 10px 22px rgba(0, 0, 0, 0.3);
  cursor: pointer;
  transform-origin: 50% 100%;
  transition: border-color 0.3s var(--ease), transform 0.3s var(--ease);
}

/* Square and ruled, like the ruler's chapter markers: these are places to go
   rather than actions, so they do not take the round filled button shape. */
.card:hover,
.card:focus-visible {
  border-color: var(--gold);
  transform: translateY(-0.45rem);
}

.card__thumb {
  display: block;
  aspect-ratio: 4 / 3;
  margin-bottom: 0.7rem;
  overflow: hidden;
  border-radius: 2px;
  background: color-mix(in srgb, currentColor 12%, transparent);
}

.card__thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }

.card__hint {
  display: block;
  margin-top: 0.55rem; padding-top: 0.5rem;
  border-top: 1px solid color-mix(in srgb, currentColor 28%, transparent);
  font-size: 0.62rem; line-height: 1.35;
  opacity: 0.6;
}

.card:hover .card__hint,
.card:focus-visible .card__hint { opacity: 0.9; }

.card__n {
  display: block;
  font-size: 0.6rem; font-weight: 700; letter-spacing: 0.2em;
  opacity: 0.6;
}

.card__name {
  display: block;
  margin-top: 0.3rem;
  font-family: var(--font-display); font-weight: 700;
  font-size: 0.88rem; line-height: 1.15;
  hyphens: auto;
}

.card__role {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.66rem; line-height: 1.3;
  opacity: 0.62;
}

/* Le tessere partono dentro il portafoglio - spinte in basso dietro la
   patta e un po' piu' piccole - e ne escono aprendosi a ventaglio. --f e'
   scritta da main.js per ognuna, sfalsata, cosi' escono una dopo l'altra
   invece che tutte insieme. */
.is-animated .wallet__slot {
  transform:
    translate(
      calc(var(--dx) * var(--f, 0)),
      calc(var(--dy) * var(--f, 0) + (1 - var(--f, 0)) * var(--w) * 0.42))
    rotate(calc(var(--rot) * var(--f, 0)))
    scale(calc(0.82 + 0.18 * var(--f, 0)));
  transform-origin: 50% 100%;
}

/* Spread wide enough that each card's name clears the one in front of it:
   fanned tighter they overlapped and you read four numbers and no names. */
/* With the engine off nothing writes --f, so the fan never opens and the four
   would sit in a pile with only the top one showing. Here they are simply a
   row of four cards. */
.is-static .wallet__cards {
  position: static; height: auto;
  display: flex; flex-wrap: wrap; gap: 0.7rem;
  margin-bottom: 1.2rem;
}
.is-static .wallet__slot {
  position: static;
  width: auto; margin: 0;
  flex: 1 1 7.5rem;
}

/* Tutto in frazioni della larghezza del portafoglio, non in rem: cosi' il
   ventaglio scala insieme all'oggetto e una sola taratura vale a ogni
   misura di schermo. Con valori fissi si rompeva a ogni formato - o le
   tessere coprivano il sottotitolo, o non entravano piu' nel portafoglio. */
.wallet__slot:nth-child(1) { --dx: calc(var(--w) * -0.62);  --dy: calc(var(--w) * -0.133); --rot: -8deg; z-index: 1; }
.wallet__slot:nth-child(2) { --dx: calc(var(--w) * -0.207); --dy: calc(var(--w) * -0.267); --rot: -2.6deg; z-index: 2; }
.wallet__slot:nth-child(3) { --dx: calc(var(--w) *  0.207); --dy: calc(var(--w) * -0.267); --rot:  2.6deg; z-index: 3; }
.wallet__slot:nth-child(4) { --dx: calc(var(--w) *  0.62);  --dy: calc(var(--w) * -0.133); --rot:  8deg; z-index: 4; }

@media (max-width: 900px) {
  .work__head { grid-template-columns: minmax(0, 1fr); }
  /* Nessuna eccezione: il ventaglio e' in frazioni della larghezza del
     portafoglio, quindi si rimpicciolisce da solo. */
  .wallet { --w: min(78vw, 22rem, 52vh); }
  /* Su uno schermo stretto il ventaglio si chiude: aperto com'e' sul grande
     sarebbe largo una volta e mezza la finestra. */
  .wallet__slot:nth-child(1) { --dx: calc(var(--w) * -0.42); }
  .wallet__slot:nth-child(2) { --dx: calc(var(--w) * -0.14); }
  .wallet__slot:nth-child(3) { --dx: calc(var(--w) *  0.14); }
  .wallet__slot:nth-child(4) { --dx: calc(var(--w) *  0.42); }
}

.work__title {
  margin: 0;
  padding-block: 0;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.1rem, 7.5vw, 5.5rem);
  line-height: 0.95;
  letter-spacing: -0.015em;
  text-transform: uppercase;
  color: currentColor;
}

.work__title em {
  font-family: var(--font-script);
  font-style: normal;
  font-size: 1.15em;
  text-transform: none;
  letter-spacing: 0;
}

.work__sub {
  margin: 0.7rem auto 0;
  max-width: 34rem;
  font-size: 1.05rem;
  color: currentColor;
  opacity: 0.72;
}

/* --- A project, opened ---------------------------------------------------

   With the engine running a panel is a screen of its own that comes up over
   the page when you pick its card. With it off they are simply four blocks
   one after the other, so the page still reads end to end.
   ------------------------------------------------------------------------ */

.is-animated .panel {
  position: fixed;
  inset: 0;
  z-index: 70;
  margin: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 0;
  visibility: hidden;
  transform: translateY(1.5rem);
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease),
              visibility 0.4s var(--ease);
  box-shadow: none;
}

.is-animated .panel.is-open {
  opacity: 1;
  visibility: visible;
  transform: none;
}

/* As an overlay the panel starts where the held column will stick, so at the
   top of it the picture is already clear of the ruler. The tall top padding
   belonged to the stacked-card version and here only pushed the photo down
   under the bar. */
/* No top padding on the panel itself: with one, the held box starts that far
   down the scrollport and only reaches its stuck position after you scroll,
   and in that first stretch the picture hangs below the ruler. The clearance
   for the menu is moved inside the two columns instead. */
.is-animated .panel {
  padding-block: 0 clamp(4rem, 9vw, 7rem);
}

.is-animated .panel__text {
  padding-block-start: calc(var(--nav-h) + clamp(1.5rem, 4vh, 3rem));
}

.has-panel { overflow: hidden; }

.panel__close {
  position: absolute;
  top: clamp(0.75rem, 2vh, 1.5rem);
  right: clamp(0.75rem, 2vw, 1.5rem);
  z-index: 5;
  width: 2.75rem; height: 2.75rem;
  display: grid; place-items: center;
  margin: 0; padding: 0;
  font: inherit; font-size: 1.6rem; line-height: 1;
  color: inherit;
  background: color-mix(in srgb, currentColor 14%, transparent);
  border: 0; border-radius: 50%;
  cursor: pointer;
  transition: background 0.3s var(--ease);
}

.panel__close:hover,
.panel__close:focus-visible { background: color-mix(in srgb, currentColor 26%, transparent); }

.is-static .panel__close { display: none; }

.panel {
  position: relative;
  /* The colour arrives gradually rather than as a step, the way the wash did
     when this was a ribbon. The blend finishes inside the top padding, so no
     text ever sits on the in-between colour and lose its contrast. */
  background: linear-gradient(to bottom,
    var(--ch-from, var(--ch-bg, var(--cream))) 0,
    var(--ch-bg, var(--cream)) clamp(5rem, 11vw, 10rem));
  color: var(--ch-fg, var(--bordeaux-ink));
  /* The overlap is the card edge: each chapter starts before the one above
     has finished, so it reads as sliding over it rather than following it. */
  margin-block-start: clamp(-3.5rem, -6vw, -2rem);
  padding-block: clamp(6rem, 13vw, 12rem) clamp(5rem, 11vw, 10rem);
  padding-inline: var(--gutter);
  box-shadow: 0 -24px 60px rgba(61, 0, 0, 0.18);
}

/* Le etichette dentro i pannelli seguono il colore del capitolo. Erano
   inchiodate a --bordeaux-soft, che su un fondo bordeaux da' un contrasto di
   1,51: "THE BRIEF", "OUTPUT" e il titolone "WHAT I DID" erano di fatto
   invisibili. Non dipende dai colori scelti - succedeva gia' col pannello 01,
   che e' sempre stato bordeaux. */
.panel .label { color: color-mix(in srgb, var(--ch-fg, var(--bordeaux-ink)) 72%, transparent); }

/* Il titolo del blocco centrale e' un titolo, non un'etichetta: sta piu' su. */
.panel .ch__block--star .label { color: color-mix(in srgb, var(--ch-fg, var(--bordeaux-ink)) 90%, transparent); }

/* The first card gets a hard edge on purpose. The bag section above ends
   cream; if this one faded in from cream too there would be nothing to see
   where one section stops and the other starts. */
.is-static .panel:first-of-type { margin-block-start: 0; box-shadow: none; }

.panel__inner {
  display: grid;
  grid-template-columns: minmax(0, 34%) minmax(0, 1fr);
  gap: clamp(2rem, 6vw, 6rem);
  max-width: var(--wrap);
  margin-inline: auto;
}

/* The pictures hold still while the words go past. They are company for the
   text, so they stay put and small and let it do the work. */
/* The pictures take the width of their column, whatever that is. Their old
   fixed pixel widths came from the ribbon, where width was free; here a 660px
   figure simply spilled out of a 400px column and sat under the text.

   They also have to fit the screen together: a column taller than the
   viewport cannot be held still, it just scrolls, and the whole point of
   this side is that it holds. So the images share what height there is and
   scale down to their ratio rather than being cropped. */
/* One picture at a time, each with the whole column to itself. Sharing the
   height between them made an Instagram post 147px wide - too small to read
   as a post at all, which is the only reason it is here. They swap as you
   read down the chapter. */
/* The held box is exactly the screen minus the menu above and the ruler
   below, so a picture inside it can never reach either. */
.panel__hold {
  box-sizing: border-box;
  height: calc(100svh - var(--ruler-h));
}

.panel__hold .shot {
  position: absolute;
  /* The clearance goes here, not on the box: `inset: 0` resolves against the
     padding box, so padding on the held box did nothing and the picture ran
     up under the menu. */
  inset: calc(var(--nav-h) + clamp(1.5rem, 4vh, 3rem)) 0 0 0;
  width: 100%;
  display: flex; flex-direction: column;
  opacity: 0;
  transition: opacity 0.55s var(--ease);
}

.panel__hold .shot.is-on { opacity: 1; }

/* With the engine off there is nothing to swap them, so they all show. */
.is-static .panel__hold { height: auto; }
.is-static .panel__hold .shot { position: relative; inset: auto; opacity: 1; }

.panel__hold .shot img {
  /* Full column width so a lazy picture still has a box before it loads:
     with `width: auto` it has no intrinsic size yet and collapses to zero. */
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  height: auto;
  object-fit: contain;
  object-position: left top;
}

/* The column itself is an ordinary grid cell; the thing that holds still is
   the box inside it. Sticky applied to the grid item was being offset by its
   own `top` instead of pinned by it, which put the picture a padding's worth
   too low and slid it under the ruler. */
.panel__media { grid-column: 1; grid-row: 1; }

.panel__hold {
  position: sticky;
  top: 0;
  display: flex; flex-direction: column;
  gap: clamp(1rem, 2.5vw, 2rem);
}

/* One picture on its own gets the whole height to itself: centred against
   the text beside it and allowed a little more width, because a single small
   image floating at the top of an empty column just looks lost. */
.panel__media--single { justify-content: center; }

.panel__media--single .panel__hold .shot {
  width: calc(100% + clamp(0.75rem, 2.5vw, 2.5rem));
}

.panel__text {
  grid-column: 2;
  grid-row: 1;
  display: flex; flex-direction: column;
  gap: clamp(3.5rem, 9vh, 7rem);
  padding-block-end: clamp(2rem, 6vh, 5rem);
}

/* Each block arrives from just below and settles. --in is written by main.js,
   0 before it is reached and 1 once it is in place; 1 is the default so the
   page reads whole with the engine off. */
.is-animated .panel__text > * {
  opacity: var(--in, 1);
  transform: translateY(calc((1 - var(--in, 1)) * 2.2rem));
}

/* --- The opening block: the oversized name ------------------------------ */

/* In the ribbon this was max-content and nowrap, so the name could bleed off
   the screen edge. In a column that bleed is just a horizontal scrollbar:
   the title wraps and stays inside its own column. */
.ch__open { width: auto; }

.ch__n {
  margin: 0 0 1rem;
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.22em;
  opacity: 0.65;
}

/* Deliberately allowed to run wider than its column: the name bleeds past
   the panel edge, the way the reference site does it. */
.ch__title {
  margin: 0 0 0.75rem;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.4rem, 6.4vw, 5.6rem);
  line-height: 0.92;
  letter-spacing: -0.025em;
  text-transform: uppercase;
}

.ch__role { margin: 0; font-size: 1.02rem; opacity: 0.75; max-width: 34ch; }

/* --- The oversized figure ----------------------------------------------- */

.ch__big {
  flex: 0 0 auto;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(3rem, 8vw, 7.5rem);
  line-height: 0.85;
  letter-spacing: -0.03em;
  white-space: nowrap;
}

/* line-height 0.85 pulls the line box in tighter than the digits themselves,
   so at this size the figure hangs below its own box and lands on the caption
   underneath. The padding gives the glyphs the room the line box does not. */
.ch__big > span {
  display: block;
  padding-bottom: 0.12em;
}

.ch__big em {
  display: block;
  max-width: 14ch;
  margin-top: 0.9rem;
  font-family: var(--font-body); font-style: normal; font-weight: 700;
  font-size: 0.7rem; letter-spacing: 0.16em; line-height: 1.5;
  text-transform: uppercase;
  white-space: normal;
  opacity: 0.7;
}

/* --- Text blocks -------------------------------------------------------- */

.ch__block { width: 100%; max-width: 44rem; }
.ch__block--wide { max-width: none; }
.ch__block--out { max-width: 40rem; }

.ch__lead {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 3vw, 2.05rem);
  line-height: 1.4;
}

.ch__out { margin: 0; font-size: clamp(1.15rem, 2.3vw, 1.45rem); line-height: 1.55; }

.ch__sign {
  margin: 1.5rem 0 0;
  font-family: var(--font-script);
  font-size: clamp(1.6rem, 3.5vw, 2.4rem);
  line-height: 1.15;
}

.ch__quote {
  flex: 0 0 auto;
  width: 100%;
  margin: 0;
  padding-left: clamp(1rem, 2vw, 1.5rem);
  border-left: 3px solid currentColor;
  font-family: var(--font-display);
  font-weight: 700; font-style: italic;
  font-size: clamp(1.45rem, 3.2vw, 2.3rem);
  line-height: 1.35;
}

.ch__quote cite {
  display: block; margin-top: 0.85rem;
  font-family: var(--font-body); font-style: normal; font-weight: 400;
  font-size: 0.68rem; letter-spacing: 0.12em; text-transform: uppercase;
  opacity: 0.65;
}

/* --- Images ------------------------------------------------------------- */

.shot { flex: 0 0 auto; margin: 0; }

.shot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 10px;
}

/* The third term is the one that matters on a short laptop screen: these
   are fixed-width figures, so without it a shot that fits a tall window is
   taller than the panel once it swells at the centre. It only bites below
   about 700px of viewport height; on a normal screen the pixel cap wins. */
/* A portrait shot is not sized, it is the height of the screen: it stretches
   the whole panel and reaches down past the ruler, which floats over it. It
   is the one thing here that never changes size - it is already as big as it
   can get, and swelling it further would only crop it. */
/* Small on purpose. These pictures are company for the words, not the
   subject: blown up they only showed how ordinary they are. */
.shot--tall   { width: min(34vw, 215px, 27vh); }
.shot--post   { width: min(40vw, 265px, 33vh); }

.shot--square { width: min(70vw, 470px, 56vh); }
.shot--wide   { width: min(90vw, 660px, 90vh); }

.shot--tall img   { aspect-ratio: 9 / 16; }
/* A published Instagram post, cropped to the creative itself: it is already
   4:5, so nothing gets chopped and no half-words of app chrome survive. */
/* The whole post, chrome included: the account row, the like bar, the caption
   and the date. Cropped to the picture alone it read as someone else's
   artwork rather than as something she published. */
.shot--post img   { aspect-ratio: 74 / 125; }
.shot--square img { aspect-ratio: 1; }
.shot--wide img   { aspect-ratio: 16 / 10; }

/* A page shot is wide and short by nature. Forcing it into the same 16/10
   as the others meant object-fit cutting a quarter of the width off, which
   took either the headline or the photo with it. */
.shot--page img   { aspect-ratio: 2 / 1; }

/* Who owns what. Showing a client's post in a portfolio is ordinary practice,
   but only if the reader can tell which part of it is hers. */
.shot__credit {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.62rem;
  line-height: 1.45;
  opacity: 0.68;
}

.shot figcaption {
  margin-top: 0.6rem;
  font-size: 0.72rem; line-height: 1.4;
  opacity: 0.7;
}

.shot--wide .browser__bar { border-radius: 10px 10px 0 0; }
.shot--wide .browser__bar + img { border-radius: 0 0 10px 10px; }

/* --- Small parts reused inside chapters --------------------------------- */

.ticks { list-style: none; margin: 0; padding: 0; }

.ticks li {
  padding: 0.8rem 0 0.8rem 1.6rem;
  border-bottom: 1px solid color-mix(in srgb, currentColor 22%, transparent);
  position: relative;
  font-size: 0.98rem; line-height: 1.55;
}

.ticks li::before {
  content: ""; position: absolute; left: 0; top: 1.5em;
  width: 0.9rem; height: 1px; background: currentColor;
}

.ticks li:last-child { border-bottom: 0; }

/* --- What she actually did ---------------------------------------------- */

/* The one thing in this section that is hers rather than the client's. It
   gets the width, the size and the entrance: the block hangs back at the
   middle of the screen and the three items land in turn, --t per item coming
   from main.js. Default 1, so with the engine off the list is simply there. */
/* Full width of its column. The old fixed width and the big side margins
   existed to buy the block room to hang back in the ribbon; in a column they
   only pushed it off the screen. */
.ch__block--star { width: 100%; }

/* The heading holds still and large while the items land under it. Lora
   against the Playfair of the list: two voices, so the title reads as a
   title and not as a fourth bullet. */
.ch__block--star .label {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: clamp(1.3rem, min(3vw, 4.2vh), 2.5rem);
  line-height: 1.05;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  opacity: 1;
  margin: 0 0 1.4rem;
  padding-bottom: 0.9rem;
  border-bottom: 2px solid currentColor;
}

.ticks--star li {
  display: grid;
  grid-template-columns: minmax(0, 8.5rem) minmax(0, 1fr);
  align-items: baseline;
  gap: 0.3rem 1.4rem;
  padding: clamp(0.55rem, 1.5vh, 1rem) 0;
  opacity: var(--t, 1);
  transform:
    translateX(calc((1 - var(--t, 1)) * 2.5rem))
    scale(calc(0.94 + 0.06 * var(--t, 1)));
  transform-origin: 0 50%;
}

/* The competence the line is about, named. It is what the row is filed
   under, which is also what fills the width the list was wasting. */
.tick__key {
  font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  line-height: 1.5;
  opacity: 0.62;
}

.tick__what {
  font-family: var(--font-display);
  font-size: clamp(1rem, min(2.2vw, 3.1vh), 1.6rem);
  line-height: 1.32;
}

.ticks--star li::before { display: none; }

/* What she worked in, on this project rather than in general. A list under a
   rule, not a row of pills: on this site round-and-filled means you can click
   it, and there is nothing to click here. */
.kit__label {
  margin: clamp(0.9rem, 2vh, 1.6rem) 0 0.6rem;
  padding-top: clamp(0.7rem, 1.6vh, 1.1rem);
  border-top: 1px solid color-mix(in srgb, currentColor 30%, transparent);
  font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  opacity: 0.62;
}

/* Named apart from the .tools block in Skills, which is a different thing:
   that one is the whole toolbox and paints itself bordeaux, which would be
   invisible on the dark chapters. This one follows the chapter's own colour. */
.kit {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap;
  gap: 0.35rem 1.15rem;
  font-size: 0.95rem;
}

.kit li + li { position: relative; }
.kit li + li::before {
  content: ""; position: absolute; left: -0.62rem; top: 0.42em;
  width: 1px; height: 0.9em;
  background: color-mix(in srgb, currentColor 45%, transparent);
}

.smart { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.9rem; }

.smart li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline;
  gap: 0.25rem 1.25rem;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid color-mix(in srgb, currentColor 22%, transparent);
}

.smart__metric {
  grid-row: 1 / span 2;
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(1.75rem, 4vw, 2.5rem); line-height: 1;
}

.smart__what { font-size: 0.95rem; line-height: 1.45; }
.smart__when { font-size: 0.66rem; letter-spacing: 0.16em; text-transform: uppercase; opacity: 0.7; }

.tactics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(175px, 1fr));
  gap: clamp(0.85rem, 2vw, 1.5rem);
  list-style: none; margin: 0; padding: 0;
}

.tactic { border-top: 2px solid currentColor; padding-top: 0.9rem; }
.tactic__n { margin: 0; font-size: 0.66rem; font-weight: 700; letter-spacing: 0.16em;
             text-transform: uppercase; opacity: 0.7; }
.tactic__name {
  margin: 0.35rem 0 0.5rem;
  font-family: var(--font-display); font-weight: 700;
  font-size: 1.08rem; line-height: 1.25;
}
.tactic__desc { margin: 0; font-size: 0.88rem; line-height: 1.5; opacity: 0.85; }

.budget { list-style: none; margin: 0; padding: 0; }

.budget li {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline; gap: 0.75rem;
  padding: 0.65rem 0 0.8rem;
  border-bottom: 1px solid color-mix(in srgb, currentColor 22%, transparent);
  position: relative;
}

.budget li::after {
  content: ""; position: absolute; left: 0; bottom: -1px;
  width: var(--pct); height: 3px; background: currentColor;
  transform: scaleX(1); transform-origin: 0 50%;
  transition: transform 0.9s var(--ease-out);
}

.is-animated [data-reveal]:not(.is-in) .budget li::after { transform: scaleX(0); }

.budget__k { font-size: 0.95rem; }
.budget__v { font-family: var(--font-display); font-weight: 700; font-size: 1.05rem;
             white-space: nowrap; }

.xp { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.9rem; }
.xp li { display: grid; grid-template-columns: minmax(0, 11rem) minmax(0, 1fr);
         align-items: center; gap: 1rem; }
.xp__name { font-size: 0.92rem; }
.xp__bar { display: block; height: 8px; border-radius: 999px;
           background: color-mix(in srgb, currentColor 18%, transparent); overflow: hidden; }
.xp__bar i { display: block; height: 100%; width: var(--w); background: currentColor;
             transform: scaleX(1); transform-origin: 0 50%;
             transition: transform 1s var(--ease-out); }

.is-animated [data-reveal]:not(.is-in) .xp__bar i { transform: scaleX(0); }

.browser__bar {
  display: flex; align-items: center; gap: 0.4rem;
  padding: 0.5rem 0.75rem;
  background: var(--cream-deep);
  border-bottom: 1px solid rgba(85, 0, 0, 0.14);
}

.browser__bar > span { width: 8px; height: 8px; border-radius: 50%; background: rgba(85, 0, 0, 0.25); }
.browser__url { margin: 0 0 0 0.5rem; font-size: 0.7rem; color: var(--bordeaux-soft); }

@media (max-width: 560px) { .xp li { grid-template-columns: 1fr; gap: 0.3rem; } }

/* --- The ruler ---------------------------------------------------------- */

/* Transparent, so the wash runs behind it and the strip does not cut the
   section in two. Everything in here rides on the interpolated text colour. */
.ruler {
  position: fixed; inset: auto 0 0 0;
  z-index: 80;
  opacity: 0; visibility: hidden;
  transition: opacity 0.35s var(--ease), visibility 0.35s var(--ease);
  padding: clamp(2rem, 5vh, 3.5rem) var(--gutter) clamp(1rem, 3vh, 1.75rem);
  color: var(--wfg, var(--bordeaux-ink));
  pointer-events: none;
  /* A scrim in the current chapter's own colour. Without it the labels sit
     on top of whatever paragraph happens to be passing underneath, and both
     become unreadable. --wbg is written by main.js from the active card. */
  background: linear-gradient(to bottom,
    transparent 0,
    color-mix(in srgb, var(--wbg, #fff5ec) 70%, transparent) 26%,
    var(--wbg, #fff5ec) 58%);
}
.ruler__item { pointer-events: auto; }

.has-panel .ruler { opacity: 1; visibility: visible; }

.is-static .ruler { position: static; opacity: 1; visibility: visible; }

/* Not a progress bar: a scrollbar laid on its side. The rail stays faint so
   it disappears into whatever picture is running behind it; only the quarter
   you are actually in comes forward. */
.ruler__ticks {
  position: relative;
  height: 4px;
  margin-bottom: 0.7rem;
  border-radius: 2px;
  /* Alpha in the colour, not `opacity`: opacity would take the thumb down
     with it, and the thumb is the one thing that has to stay solid. */
  background: color-mix(in srgb, currentColor 24%, transparent);
}

.ruler__ticks::after {
  content: ""; position: absolute; top: -1px; bottom: -1px; left: 0;
  /* One chapter wide, wherever the chapter count lands. --chapters is set by
     main.js from the markup, so adding a project does not silently leave the
     thumb the wrong size. */
  width: calc(100% / var(--chapters, 4));
  border-radius: 3px;
  background: currentColor;
  transform: translateX(calc(var(--p, 0) * (var(--chapters, 4) - 1) * 100%));
}

.ruler__items { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 0.5rem; }

/* These ARE buttons, but they are chapter markers rather than actions:
   flat, left-aligned, underlined when current. Never pill-shaped. */
.ruler__item {
  display: flex; flex-direction: column; align-items: flex-start; gap: 0.15rem;
  background: none; border: 0; border-top: 2px solid transparent;
  padding: 0.6rem 0 0; margin: 0;
  font: inherit; text-align: left; cursor: pointer;
  color: currentColor; opacity: 0.5;
  transition: opacity 0.3s var(--ease), border-color 0.3s var(--ease), color 0.3s var(--ease);
}

.ruler__item:hover { opacity: 0.85; }
.ruler__item.is-on { opacity: 1; border-top-color: currentColor; }

.ruler__i { font-size: 0.62rem; font-weight: 700; letter-spacing: 0.18em; }
.ruler__label {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(0.78rem, 1.4vw, 1rem); line-height: 1.2;
}

/* --- Work on a narrow screen -------------------------------------------- */

@media (max-width: 900px) {
  .panel__inner { grid-template-columns: minmax(0, 1fr); gap: clamp(1.5rem, 5vw, 2.5rem); }
  /* Passare a una colonna sola non basta: i due figli hanno grid-column 1 e 2
     scritti a mano, e il testo restava inchiodato alla 2. Il browser creava
     quella colonna implicita, la dimensionava sul contenuto del testo e alla
     colonna definita non restava niente - misurato: `0px 311px`, con ogni
     figura schiacciata a 12px. Le foto dei lavori non si vedevano su nessun
     telefono, in nessuno dei quattro pannelli. Vanno rimessi in colonna 1 e
     lasciati impilare. */
  .panel__media, .panel__text { grid-column: 1; grid-row: auto; }
  /* Nothing to hold still against: one column, so the pictures simply sit
     in the flow between the blocks. */
  /* One column: nothing to hold still against, so every picture goes back
     into the flow, one under the other. */
  .panel__media, .panel__hold { position: static; height: auto; }
  .panel__hold .shot {
    position: relative; inset: auto;
    opacity: 1;
    max-width: 22rem;
  }
  .panel__text { gap: clamp(2.25rem, 7vh, 3.5rem); }
}

/* --- Skills / languages / tools ----------------------------------------- */

.skills__cols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
  gap: clamp(1.75rem, 4vw, 3rem);
}

/* Sei voci in due colonne di tre. Serve da quando la colonna "How I work" e'
   uscita: con un solo gruppo la griglia sopra dava una colonna larga quanto
   la pagina, e "Copywriting" si trascinava dietro mezzo schermo di vuoto.
   Il flusso e' per colonna e le righe sono fissate a tre, cosi' il fondo di
   ogni colonna e' sempre la terza voce e il filetto si toglie li' senza
   dipendere da quante colonne ci entrano. Legato a otto voci: cambiandone il
   numero, il 4n va rifatto. */
.skills__list {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-auto-flow: column; grid-template-rows: repeat(4, auto);
  column-gap: clamp(1.75rem, 4vw, 3rem);
}

.skills__list li {
  padding: 0.55rem 0;
  border-bottom: 1px solid rgba(85, 0, 0, 0.16);
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.05rem, 2.2vw, 1.3rem);
  color: var(--bordeaux);
}

.skills__list li:nth-child(4n) { border-bottom: 0; }

/* Sotto le due colonne non ci stanno: torna una fila sola e il filetto si
   toglie solo in fondo, altrimenti sparisce anche a meta' elenco. */
@media (max-width: 34rem) {
  .skills__list { grid-auto-flow: row; grid-template-rows: none; }
  .skills__list li:nth-child(4n) { border-bottom: 1px solid rgba(85, 0, 0, 0.16); }
  .skills__list li:last-child { border-bottom: 0; }
}

.langs, .certs, .toolsblock {
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  padding-top: clamp(2rem, 4vw, 3rem);
  border-top: 1px solid rgba(85, 0, 0, 0.16);
}

.langs__list, .certs__list {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: clamp(0.85rem, 2.5vw, 1.5rem);
}

.langs__list li, .certs__list li { border-top: 2px solid var(--bordeaux); padding-top: 0.7rem; }

.certs__list { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.certs__name { font-size: 1.05rem; }

.langs__name, .certs__name {
  display: block;
  font-family: var(--font-display); font-weight: 700; font-size: 1.2rem;
  color: var(--bordeaux);
}

.langs__lvl, .certs__lvl {
  display: block; font-size: 0.68rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--bordeaux-soft);
}

/* Tools: squared cells with a hairline. Deliberately not pills. */
/* A wrapped list divided by hairlines: no grid cells, so no ghost block
   where the last row runs out of items. Nothing here looks pressable. */
.tools {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center;
  column-gap: 0; row-gap: 0.35rem;
}

.tools li {
  padding: 0.35rem 1.15rem;
  font-size: 0.9rem;
  color: var(--bordeaux);
  border-left: 1px solid rgba(85, 0, 0, 0.3);
}

.tools li:first-child { border-left: 0; }

/* Di questo lavoro le appartiene il testo e non la grafica, quindi al posto
   della figura c'e' il testo composto: stessa forma di una .shot - stesso
   raggio, stessa didascalia sotto - ma dentro non c'e' niente di nessun altro.
   Fondo crema perche' il pannello 01 e' bordeaux pieno. */
/* La larghezza va dichiarata come per le altre .shot--*: senza, dentro la
   colonna flex la carta si stringe al contenuto e su schermo stretto
   collassava a 35px. Qui non c'e' un rapporto d'immagine da rispettare,
   quindi niente terzo termine legato all'altezza. */
.shot--words { width: min(90vw, 470px); }

.shot--words .words {
  border-radius: 10px;
  background: var(--cream); color: var(--bordeaux-ink, var(--bordeaux));
  padding: clamp(1.1rem, 3vw, 1.9rem);
}

/* Corpo fisso, non legato al viewport: la carta e' larga uguale su desktop e
   su telefono, quindi un testo che rimpicciolisce sullo schermo piccolo va
   nella direzione sbagliata - scendeva a 12,5px. */
.shot--words .words p {
  margin: 0 0 0.85em;
  font-size: 0.88rem; line-height: 1.62;
}

.shot--words .words p:last-child { margin-bottom: 0; }

/* --- Footer / contact --------------------------------------------------- */

.foot { background: var(--bordeaux-ink); color: var(--cream); overflow: hidden; }

.foot__marquee {
  border-block: 1px solid rgba(255, 245, 236, 0.2);
  overflow: hidden; padding-block: 0.7rem;
}

.foot__track {
  display: flex; width: max-content; gap: 1.75rem;
  animation: marquee 34s linear infinite;
  font-family: var(--font-display);
  font-size: clamp(0.9rem, 2vw, 1.15rem); font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase; white-space: nowrap;
  color: rgba(255, 245, 236, 0.85);
}

@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

.foot__inner {
  padding-top: clamp(3rem, 7vw, 5rem);
  padding-bottom: clamp(2rem, 5vw, 3rem);
  text-align: center;
}

.foot__kicker {
  margin: 0;
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(1.75rem, 5.5vw, 3.25rem);
  line-height: 1.05; text-transform: uppercase;
}

.foot__script {
  margin: 0.1rem 0 clamp(2.25rem, 5vw, 3rem);
  font-family: var(--font-script);
  font-size: clamp(2.25rem, 8vw, 4.5rem); line-height: 1.1;
}

.foot__list {
  display: grid; gap: 0.9rem; justify-content: center;
  list-style: none; margin: 0 0 clamp(2.25rem, 5vw, 3rem); padding: 0; text-align: left;
}

.foot__list li {
  display: grid; grid-template-columns: 7.5rem minmax(0, 1fr);
  align-items: baseline; gap: 1rem;
}

.foot__list .label { margin: 0; color: rgba(255, 245, 236, 0.6); }
.foot__list a { color: var(--cream); text-underline-offset: 3px; overflow-wrap: anywhere; }

.foot__legal {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  padding-block: 1.25rem;
  border-top: 1px solid rgba(255, 245, 236, 0.16);
  font-size: 0.68rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: rgba(255, 245, 236, 0.6);
}

.foot__legal p { margin: 0; }
.foot__top { color: inherit; text-decoration: none; border-bottom: 1px solid currentColor; }

@media (max-width: 560px) { .foot__list li { grid-template-columns: 1fr; gap: 0.15rem; } }

/* --- Reveals ------------------------------------------------------------ */

/* Same rule: invisible only once JS has taken responsibility for showing it. */
.is-animated [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}

.is-animated [data-reveal].is-in { opacity: 1; transform: none; }

/* --- Motion off ---------------------------------------------------------
   Reached either because the visitor's system asks for reduced motion, or
   because they switched motion off themselves. The rules hang off .is-static
   rather than the media query so the on-page toggle can override the system
   default in both directions.

   The goal here is a well-composed static page, not the animated one with
   its moving parts frozen mid-air.
   ---------------------------------------------------------------------- */

.is-static { scroll-behavior: auto; }

.is-static *, .is-static *::before, .is-static *::after {
  animation-duration: 0.01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.01ms !important;
}

.is-static .pin { position: static; height: auto; overflow: visible; }

/* The bag section unrolls into a poster: title, bag, the six objects, then
   the six captions. */
.is-static .bag { height: auto; padding-block: var(--section-y); background: var(--cream); }
.is-static .bag__pin { position: static; height: auto; overflow: visible; }

.is-static .bag__stage {
  display: flex; flex-direction: column; align-items: center;
  gap: clamp(1.75rem, 5vw, 3rem);
}

.is-static .bag__title { position: static; transform: none; }

.is-static .bag__tote {
  position: static; transform: none; opacity: 1;
  width: min(44vw, 300px);
}

.is-static .bag__objects {
  position: static;
  display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-end;
  gap: clamp(1.5rem, 5vw, 3.5rem);
}

.is-static .obj { --u: clamp(90px, 12vw, 130px); }

.is-static .bag__obj {
  position: static;
  opacity: 1;
  transform: rotate(var(--r));
}

.is-static .bag__texts {
  position: static; transform: none;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: clamp(1.5rem, 4vw, 2.5rem);
  width: min(100%, var(--wrap));
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* The captions are absolutely placed on alternating sides when animated;
   here they go back into normal flow inside the grid. */
.is-static .bag__text,
.is-static .bag__text:nth-child(odd),
.is-static .bag__text:nth-child(even) {
  position: static;
  inset: auto;
  width: auto;
  padding-inline: 0;
  text-align: left;
  opacity: 1;
  transform: none;
}
.is-static .bag__name { font-size: clamp(1.25rem, 2.3vw, 1.65rem); }

/* The keywords become a line under the title; the panel would be an empty
   frame without its scroll behaviour. */
.is-static .about__grid { grid-template-columns: 1fr; gap: 0; }

.is-static .about__sticky { position: static; display: block; }

.is-static .about__panel {
  aspect-ratio: auto;
  max-height: none;
  display: flex; flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 1.25rem;
  padding: 0 0 clamp(1.5rem, 4vw, 2.5rem);
  background: none;
  overflow: visible;
}

.is-static .about__panel::after { display: none; }
.is-static .about__photos { display: none; }

.is-static .about__word,
.is-static .about__word + .about__word {
  position: static;
  opacity: 1;
  transform: none;
  font-size: clamp(1.15rem, 2.6vw, 1.75rem);
}

.is-static .about__word + .about__word::before {
  content: "/";
  margin-right: 1.15rem;
  color: var(--gold);
}

.is-static .about__rail { display: none; }
.is-static .about__step { opacity: 1; }

/* --- The motion switch -------------------------------------------------- */

.foot__motion {
  background: none; border: 0; padding: 0; margin: 0;
  color: inherit; font: inherit;
  font-size: 0.68rem; letter-spacing: 0.12em; text-transform: uppercase;
  cursor: pointer;
  border-bottom: 1px solid currentColor;
}

@media (prefers-reduced-motion: reduce) {
  html:not(.is-animated) .foot__track,
  html:not(.is-animated) .hero__word,
  html:not(.is-animated) .hero__photo,
  html:not(.is-animated) .hero__script,
  html:not(.is-animated) .hero__scrollcue::after { animation: none; }
}

@media print {
  .nav, .readbar, .ruler, .foot__marquee { display: none; }
  .pin { position: static; height: auto; }
  [data-reveal], .slide { opacity: 1; transform: none; }
}
