/* Hero. Zone `hero-`, world layer, loaded after style.css. */

/* 1. Role plate */
.hero-role {
  background: var(--action-default);
  background-image: none;
  color: var(--text-on-action);
  border-radius: var(--radius-os);
  box-shadow: var(--elevation-rest);
}

/* Role plate in mono: display expanded caps at 26px was below the 32px floor
   and the same title already lives in the nav. D-123. */
.hero-role {
  flex-direction: row;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 var(--space-2);
  font-family: var(--type-family-mono);
  font-size: var(--type-body);
  font-weight: 600;
  letter-spacing: var(--meta-tracking);
  padding: var(--space-3) var(--space-4);
  line-height: 1.2;
}

/* Median dot returns with the single line. Decorative, so CSS, not markup. D-104. */
.hero-role-line + .hero-role-line { margin-top: 0; }

.hero-role-line + .hero-role-line::before {
  content: "\00B7";
  margin-right: var(--space-2);
}

/* Below 900: explicit stack rather than letting the dot open a line. */
@media (max-width: 900px) {
  .hero-role {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
    font-size: var(--type-small);
  }
  .hero-role-line + .hero-role-line::before { content: none; margin-right: 0; }
}

/* 2. Accent out of running text: emphasis by body weight. */
.hero-bio p strong {
  color: inherit;
  font-weight: 700;
}

/* 3. The wave. SVG, easter egg. */
#hero-wave {
  display: inline-block;
  width: 1.1em;
  height: 1.1em;
  vertical-align: -0.18em;
  cursor: pointer;
  /* Spam-clicking the wave must not select the greeting around it. */
  -webkit-user-select: none;
  user-select: none;
  /* Text ink, not yellow: it read as an emoji. */
  color: inherit;
}

#hero-wave:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
  border-radius: var(--radius-os);
}

.hero-wave-svg { width: 100%; height: 100%; overflow: visible; }

.hero-wave-shape,
.hero-wave-plate {
  transform-origin: 12px 20px;   /* le poignet, pas le centre */
}

/* Treatment A: offset registration plate. */
.hero-wave-plate {
  color: var(--action-pressed);
  opacity: 0;
  transform: translate(0, 0);
  transition:
    opacity var(--motion-state),
    transform var(--motion-state);
}

#hero-wave:hover .hero-wave-plate,
#hero-wave:focus-visible .hero-wave-plate {
  opacity: 1;
  transform: translate(2.5px, 2.5px);
}

/* Treatment B: the hand tilts. */
.hero-wave--tilt .hero-wave-plate { display: none; }

.hero-wave--tilt .hero-wave-shape {
  transition: transform var(--motion-state);
}

.hero-wave--tilt:hover .hero-wave-shape,
.hero-wave--tilt:focus-visible .hero-wave-shape {
  transform: rotate(-9deg);
}

/* The running animation stays in charge, or a hover mid-play resets it. */
#hero-wave.is-waving .hero-wave-shape,
#hero-wave.is-waving .hero-wave-plate { transition: none; }

@media (prefers-reduced-motion: reduce) {
  .hero-wave-plate,
  .hero-wave-shape { transition: none; }
}

/* 4. Metrics. A HUD, not four cards. */
/* .stats-bar declared once, in the D-141 rework below. */

/* A row of readouts separated by rules, not four boxes. */
.stats-inner {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0;
  border-top: 1px solid var(--border-default);
  border-bottom: 1px solid var(--border-default);
  padding-block: var(--rhythm-intra);
}

.stat-item {
  display: grid;
  gap: var(--space-2);
  align-content: start;
  padding-inline: var(--space-5);
  background: none;
  border: none;
  border-radius: var(--radius-none);
}

/* The rule belongs to the relation, carried by the item that follows. */
.stat-item + .stat-item { border-left: 1px solid var(--border-default); }

.stat-value {
  font-family: var(--type-family-display);
  font-variation-settings: "wdth" var(--wdth-section);
  font-size: var(--type-section);
  font-weight: 700;
  line-height: var(--display-leading);
  letter-spacing: var(--display-tracking);
  color: var(--text-primary);
}

/* Suffixes stay with the number: same ink, smaller size. */
.stat-value span { font-size: 0.62em; }

/* One figure carries the accent: a key metric, one of the allowed uses. */
.stat-item[data-lead] .stat-value { color: var(--action-default); }

.stat-label {
  font-family: var(--type-family-mono);
  font-size: var(--type-meta);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--meta-tracking);
  line-height: 1.5;
  color: var(--text-meta);
}

@media (max-width: 767px) {
  .stat-item { padding-inline: var(--space-3); }
  .stat-item + .stat-item { border-left: none; }
  .stats-inner { gap: var(--rhythm-intra) 0; }
}

/* 5. Composition */
.hero {
  /* Box from style.css. Horizontal inset removed: the hero sat 48px inside
     everything else on the page. D-213. */

  display: grid;

  /* One column: at 973 a side column strangles either the photo or the measure. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--rhythm-inter);
  align-items: start;
  padding-block: var(--rhythm-inter) 0;

  /* --hero-eyebrow-h retire avec l ancrage haut : plus aucun usage. D-110. */
}

/* Hero clears the fixed header: --header-h plus the rhythm, not the rhythm alone. */
@media (min-width: 1024px) {
  .hero {
    padding-block-start: calc(var(--header-h) + var(--rhythm-inter));
  }
}

/* No left bleed: the gutter is not empty space, it carries the panel. */
.hero-greeting,
.hero-name-row,
.hero-role {
  margin-left: 0;
}

.hero-name-row h1,
.hero-name {
  font-family: var(--type-family-display);
  font-variation-settings: "wdth" var(--wdth-hero);
  /* Title bound by available width, not by --type-hero. */
  font-size: clamp(2rem, 5.4vw, 4.75rem);
  line-height: var(--display-leading);
  letter-spacing: var(--display-tracking);
}

/* The text does not bleed: it holds the measure. */
.hero-bio p { max-width: var(--measure); }

/* Right bleed: the photo reaches the column edge, never past the page padding. */
.hero-photo-wrap {
  /* Bounded: at 560 alone under the text it filled a large void. */
  max-width: 420px;
  margin-left: auto;
  margin-right: 0;
}

/* Kept and enlarged, never filed into a card. */
.hero-photo-wrap,
.hero-aside {
  background: none;
  border: none;
  box-shadow: none;
}

@media (max-width: 1023px) {
  .hero { grid-template-columns: minmax(0, 1fr); }
  .hero-greeting,
  .hero-name-row,
  .hero-role { margin-left: 0; }
  .hero-photo-wrap { margin-right: 0; margin-left: 0; }
}

/* 6. Timeline. No cards. */
.parcours-card {
  background: var(--surface-raised);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-os);
  box-shadow: none;
}

/* Both inner levels drop the card treatment: hierarchy moves to rhythm. */
.parcours-card-inner,
.parcours-card-meta,
.parcours-card-highlight {
  background: none;
  border: none;
  border-radius: var(--radius-none);
  box-shadow: none;
}

/* Card job title in mono. D-207. */
.parcours-card-role {
  font-family: var(--type-family-mono);
  font-size: var(--type-card);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--meta-tracking);
  line-height: 1;
  color: var(--text-primary);
}

.parcours-card-studio,
.parcours-card-period {
  font-family: var(--type-family-mono);
  font-size: var(--type-meta);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--meta-tracking);
  color: var(--text-meta);
}

.parcours-card-highlight {
  font-family: var(--type-family-body);
  font-size: var(--type-body);
  line-height: 1.65;
  max-width: var(--measure);
  color: var(--text-secondary);
}

/* The avatar pushed the title 112px right, off the text alignment. */
.hero-name-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  min-width: 0;
}

.hero-name-row .hero-avatar {
  flex: 0 0 auto;
  align-self: center;
}

/* Avatar inline with the name: placed above it floated alone. */
.hero-name-row .hero-name { flex: 1 1 0; min-width: 0; }

/* Photo returns beside the content. */
/* 1560, not 1280: below it the two-column layout strangles the measure. */
@media (min-width: 1560px) {
  .hero {
    /* 470 is derived: the photo is square, top anchored at 124, bottom on 594. */
    grid-template-columns: minmax(0, 1fr) minmax(300px, 470px);
    /* Gutter 64 to 96. D-232. */
    column-gap: var(--space-9);
    row-gap: var(--rhythm-intra);
  }

  /* Availability band takes its own row. D-232. */
  .hero-content { grid-column: 1; grid-row: 1; }
  .hero-aside { grid-column: 2; grid-row: 1; }
  .hero-bottom-row { grid-column: 1 / -1; grid-row: 2; }

  /* Six dead rules removed. */
  /* Photo anchored to the bottom of the column. D-107. */
  .hero-aside {
    align-self: end;
  }

  .hero-photo-wrap {
    /* The 420 bound is lifted here only. D-062. */
    max-width: 470px;
    margin-right: 0;
  }
}

/* Title fits its column. */
.hero-name-row { min-width: 0; }

.hero-name-row .hero-name {
  min-width: 0;
  max-width: 100%;
  /* deux lignes plutot qu un debordement */
  white-space: normal;
  overflow-wrap: normal;
  font-size: clamp(2rem, 4.6vw, 4rem);
}

/* Availability band. */
.hero-info-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 0;
  background: var(--surface-raised);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-os);
  box-shadow: var(--elevation-subtle);
  overflow: hidden;
}

/* No label above its value. */
.hero-info-strip {
  width: fit-content;
  max-width: 100%;
}

.hero-strip-badge,
.hero-strip-item {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
}

/* LinkedIn glyph: without the label, the handle alone says nothing. */
.hero-strip-icon {
  width: var(--space-4);
  height: var(--space-4);
  flex-shrink: 0;
}

/* The rule belongs to the relation between two readouts. */
.hero-strip-item,
.hero-strip-mail { border-left: 1px solid var(--border-default); }

/* margin-left:auto removed: the bar now sizes to its content. D-104. */

/* Status dot: accent and OS radius. */
.availability-dot {
  width: var(--space-2);
  height: var(--space-2);
  border-radius: var(--radius-os);
  background: var(--action-default);
  box-shadow: 0 0 0 3px var(--action-ghost);
  flex: 0 0 auto;
}

/* .hero-strip-label left the markup with the labels. D-108. */
/* Legibility: --text-meta measured 4.98:1 against its neighbour. */
.availability-text {
  font-family: var(--type-family-mono);
  font-size: var(--type-meta);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--meta-tracking);
  color: var(--text-primary);
}

/* Removed with the labels: it was what stacked them. */

.hero-strip-value {
  font-family: var(--type-family-body);
  font-size: var(--type-small);
  color: var(--text-primary);
}

/* Childhood photo, inspection window. */

/* No title bar: with the label gone it was an empty band. */
/* home-legacy.css still gives the wrapper the 15%/21% annotation matte. */
.hero-photo-wrap {
  padding-block: 0;
  line-height: normal;
}

.hero-photo-stage {
  position: relative;
  width: 100%;
  line-height: 0;
}

/* Inspection zones */
.annot-group {
  position: absolute;
  inset: 0;
  /* The group captures nothing: only its zone is a target. */
  pointer-events: none;
  opacity: 1;
}

.annot-zone {
  position: absolute;
  pointer-events: auto;
  border: 1px dotted var(--photo-zone-border);
}

.annot-label {
  position: absolute;
  /* Mono carries metadata: caps, 0.08em. */
  font-family: var(--font-mono);
  font-size: var(--type-meta);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  line-height: 1.4;
  white-space: nowrap;
  padding: var(--space-1) var(--space-2);
  color: var(--photo-label-text);
  background: var(--photo-label-bg);
  border: 1px solid var(--photo-label-border);
  border-radius: var(--radius-os);
  /* No shadow: the cartouche sits on the photo, it raises nothing. */
}

/* Geometry: one modifier per subject, percentages relative to the photo. */
.annot-group--screen .annot-zone { left: 6%;  top: 2%;  width: 52%; height: 47%; }
.annot-group--screen .annot-label { left: 6%; top: calc(49% + var(--space-2)); }

.annot-group--head .annot-zone { left: 49%; top: 49%; width: 34%; height: 51%; }
.annot-group--head .annot-label { right: 17%; bottom: calc(51% + var(--space-2)); }

.annot-group--toys .annot-zone { left: 17%; top: 62%; width: 28%; height: 19%; }
.annot-group--toys .annot-label { left: 17%; top: calc(81% + var(--space-2)); }

/* Reveal on hover. */
@media (hover: none), (pointer: coarse) {
  .annot-zone { display: none; }
  /* A permanent frame would be noise. */
  .annot-zone--open { display: block; }
}

@media (hover: hover) and (pointer: fine) {
  /* One element moves per action, and it moves in opacity. */
  .annot-group {
    opacity: 0;
    transition: opacity var(--dur-state) var(--ease-in);
  }

  /* :focus-within: focus lands on the zone, not the group. */
  .annot-group:hover,
  .annot-group:focus-visible,
  .annot-group:focus-within,
  .annot-group.is-open {
    opacity: 1;
    transition-timing-function: var(--ease-out);
  }

  /* The ring sits on the zone: the group covers the whole image. */
  .annot-group:focus-visible { outline: none; }
  .annot-group:focus-visible .annot-zone,
  .annot-group .annot-zone:focus-visible {
    outline: 2px dotted var(--focus-ring);
    outline-offset: 3px;
  }
}

/* The two windows. */

/* Trigger: no appearance of its own, it inherits .annot-zone. */
.annot-zone--open {
  padding: 0;
  background: transparent;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.annot-win {
  position: fixed;
  top: 0;
  left: 0;
  z-index: var(--z-window);
  display: none;
  /* Position in transform, never top/left: it is tracked every frame. */
  transform: translate3d(var(--annot-win-x, 0px), var(--annot-win-y, 0px), 0);
}

/* No scale on open: two windows appearing is already movement. */
.annot-win.is-open {
  display: block;
  animation: annot-win-in var(--motion-structural) both;
}

/* The second window of each pair lags by one press duration. */
.annot-win--late.is-open { animation-delay: var(--dur-press); }

@keyframes annot-win-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Two windows, two ranks; the last touched comes forward. */
.annot-win.is-front { z-index: var(--z-window-front); }

/* One width rule, four modifiers that only set a variable. */
.annot-win {
  width: min(var(--annot-win-w), calc(100vw - 2 * var(--annot-win-margin)));
}

.annot-win--boxart    { --annot-win-w: var(--annot-win-boxart-w); }
.annot-win--honeytree { --annot-win-w: var(--annot-win-honeytree-w); }
.annot-win--barbatos  { --annot-win-w: var(--annot-win-barbatos-w); }
.annot-win--workbench { --annot-win-w: var(--annot-win-workbench-w); }
.annot-win--concert   { --annot-win-w: var(--annot-win-concert-w); }

.annot-win:focus-visible {
  outline: var(--focus-outline);
  outline-offset: 3px;
}

/* The handle is the title bar, as on the OS it quotes. */
.annot-win-grip {
  /* Drag on the bar only: on the whole window it would fight text selection. */
  touch-action: none;
  justify-content: flex-start;
  gap: var(--space-2);
  cursor: grab;
  user-select: none;
}

.annot-win.is-dragging .annot-win-grip { cursor: grabbing; }

.annot-win-close {
  position: relative;
  margin-left: auto;
  font-family: var(--font-system);
  font-size: var(--type-chrome);
  line-height: 1;
  cursor: pointer;
}

/* Target exceeds the drawing: the control is 14px. */
.annot-win-close::after {
  content: "";
  position: absolute;
  inset: -8px;
}

/* .win-body sets 24px, a project window inset, not a thumbnail one. */
.annot-win-body { padding: var(--space-2); }

.annot-win-img {
  display: block;
  width: 100%;
  height: auto;
}

/* One right edge. */
/* The edge becomes the measure. */
@media (min-width: 901px) {
  .hero-content {
    --hero-edge: 600px;
    --hero-avatar-size: clamp(48px, 6.8vw, 92px);
    /* Room left for the name once the avatar and its gutter are placed. */
    --hero-name-room: calc(var(--hero-edge) - var(--hero-avatar-size) - var(--space-4));
  }

  .hero-name-row { max-width: var(--hero-edge); }

  /* Avatar size from the token: two rules read it separately. */
  .hero-name-row .hero-avatar {
    width: var(--hero-avatar-size);
    height: var(--hero-avatar-size);
  }

  .hero-name-row .hero-name {
    font-size: min(calc(var(--hero-name-room) / 6.408), 5.15rem);
  }

  .hero-role {
    width: var(--hero-edge);
    font-size: calc(
      (var(--hero-edge) - var(--space-4) * 2 - var(--space-2) * 2) / 27.2
    );
  }

  .hero-bio p,
  .hero-bio-actions { max-width: var(--hero-edge); }

  /* Band no longer stretches: it left .hero-content for its own row. D-232. */
  .hero-info-strip { width: max-content; max-width: 100%; }
}

/* Same threshold as the two columns, not 901. D-231. */
@media (min-width: 1560px) {
  .hero-content {
    container-type: inline-size;

    /* Text block edge: the column, never wider than the measure. D-238. */
    --hero-text-edge: min(100cqi, var(--hero-bio-measure));
  }

  .hero-name-row { max-width: 100%; }

  /* Name back on two lines. D-237. */
  .hero-name-row .hero-name {
    font-size: clamp(
      2rem,
      calc((100cqi - var(--hero-avatar-size) - var(--space-4)) / 6.408),
      5.15rem
    );
  }

  /* Plate aligns on the bio, not the name. D-238. */
  .hero-role {
    width: var(--hero-text-edge);
    font-size: calc(
      (var(--hero-text-edge) - var(--space-4) * 2 - var(--space-2) * 2 - 2px) / 27.2
    );
  }

  .hero-bio-actions { max-width: 100%; }

  /* Bio stops before the edge: composition, not reading comfort. D-234. */
  .hero-bio p { max-width: var(--hero-text-edge); }
}

/* Band wanted 627px; at 600 it sent the button to a second line. */
@media (min-width: 901px) {
  .hero-strip-badge,
  .hero-strip-item,
  .hero-strip-mail { padding-inline: var(--space-3); }

  .hero-info-strip .hero-strip-item:not(.btn-contact) { flex: 1 1 auto; }
}

/* Metrics block. */
/* Readout board. */
.stats-bar {
  background: none;
  border: none;
  border-radius: var(--radius-none);
  padding: 0;
  /* Margin from style.css, its last live declaration there. D-213. */
  margin-block: var(--rhythm-inter);
}

.stats-inner {
  display: grid;
  /* Lead track out of the fraction, the other three equal. */
  grid-template-columns: minmax(min-content, 0.75fr) repeat(3, minmax(0, 1fr));
  /* Three rows, shared by the four columns. */
  grid-template-rows: auto auto auto;
  gap: var(--space-6) var(--space-6);
  border: none;
  padding: 0;
  /* Each readout centres on its track. D-225. */
  justify-items: center;
}

.stat-item {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  gap: var(--space-2);
  min-width: 0;
  /* A readout cannot leave its track. D-235. */
  max-width: 100%;
  padding: 0;
  background: none;
  border: none;
  text-align: center;
}

/* Separator cancelled on its own selector: two classes against two. */
.stat-item + .stat-item { border-left: none; }

/* Lead track is three quarters of a track. */
.stat-item[data-lead] { min-width: 0; }

/* First readout inset on mobile. */
.stat-item:first-child { padding: 0; }

/* Board numbers 01-04 removed. */

.stat-value {
  /* Shared baseline, not shared bottom edge: two sizes do not drop alike. */
  align-self: baseline;
  font-family: var(--type-family-display);
  font-variation-settings: "wdth" var(--wdth-section);
  font-size: var(--type-section);
  font-weight: 700;
  line-height: 1;
  letter-spacing: var(--display-tracking);
  color: var(--text-primary);
  /* Offset registration applied to type: the one link between the two layers. */
  text-shadow: 0.055em 0.055em 0 var(--plate-ink);
}

/* Suffixes stay with the number: same ink, smaller size. */
.stat-value span {
  font-size: 0.62em;
  color: inherit;
}

/* One figure carries the accent: allowed for a key metric. */
/* Lead figure grows. Documented exception to the two-size cap. */
.stat-item[data-lead] .stat-value {
  color: var(--action-default);
  font-size: calc(var(--type-section) * 1.5);
  text-shadow: 0.055em 0.055em 0 var(--action-pressed);
}

.stat-label {
  align-self: start;
  font-family: var(--type-family-mono);
  font-size: var(--type-meta);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--meta-tracking);
  line-height: 1.5;
  color: var(--text-primary);
}

/* The qualifier: what the figure covers. Mixed case, it enumerates. */
.stat-note {
  align-self: start;
  font-family: var(--type-family-mono);
  font-size: var(--type-meta);
  line-height: 1.6;
  color: var(--text-meta);
}

/* Rank centres. */
.stat-label,
.stat-note {
  text-wrap: balance;
}

@media (max-width: 900px) {
  .stats-inner {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: repeat(6, auto);
    gap: var(--space-6) var(--space-5);
  }
}

@media (max-width: 520px) {
  /* One column: the subgrid has nothing left to align and starts to hurt. */
  .stats-inner {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: none;
    grid-auto-rows: auto;
  }

  .stat-item {
    grid-row: auto;
    grid-template-rows: none;
  }
}

/* Readout block. */

/* Availability band. */
@media (max-width: 767px) {
  .hero-info-strip {
    display: grid;
    /* Three columns since Workshop joined the contact row. */
    grid-template-columns: minmax(0, 1fr) auto auto;
    width: 100%;
  }

  .hero-strip-badge,
  .hero-strip-item:not(.btn-contact) {
    grid-column: 1 / -1;
  }

  /* Rules go horizontal, except between the two contacts. */
  .hero-strip-badge,
  .hero-strip-item,
  .hero-strip-item.btn-contact { border-left: none; }

  .hero-strip-item,
  .hero-strip-mail { border-top: 1px solid var(--border-default); }

  /* Mail tap target: it was 32px wide. */
  /* Must be as specific as .hero-strip-item.btn-contact. */
  .hero-strip-mail,
  .hero-strip-item--icon.btn-contact {
    border-left: 1px solid var(--border-default);
    justify-content: center;
    min-width: 56px;
  }
}

/* Hero does not redo it. */
@media (max-width: 1023px) {
  .hero { padding-block-start: 0; }
}
