/* The resumé, below the fold of the front door: an intro you can read in ten
   seconds, then fully open entries. */

.page {
  position: relative;
  z-index: 2;
  display: grid;
  gap: var(--rhythm);
  /* Content box matched to `.stage__content` above, so the rules on the
     resumé line up with the rules under the nav rather than sitting inside
     them by an arbitrary hundred pixels. */
  max-width: calc(68rem + 2 * var(--page-pad));
  margin-inline: auto;
  padding: var(--rhythm) var(--page-pad);
  /* One hairline is what separates the front door from the document. The
     stage above it is a full screen, so nothing louder is needed. */
  border-top: 1px solid var(--rule);
}

/* ---- intro ------------------------------------------------------------- */

.intro {
  position: relative;
  display: grid;
  gap: clamp(0.85rem, 0.5rem + 1vw, 1.35rem);
  justify-items: start;
  touch-action: pan-y pinch-zoom;
}

.intro[data-dragging] {
  cursor: grabbing;
  user-select: none;
}

/* An independent acoustic domain for the resumé's opening statement. It uses
   the page padding and the following grid gap as acoustic overscan: the title
   and facts stay clear of the absorbing boundary, and the reveal source has
   real space in which to fire without changing the document's layout. */
.intro__canvas {
  position: absolute;
  top: calc(-1 * var(--rhythm));
  right: calc(-1 * var(--page-pad));
  bottom: calc(-1 * var(--rhythm));
  left: calc(-1 * var(--page-pad));
  width: calc(100% + var(--page-pad) + var(--page-pad));
  height: calc(100% + var(--rhythm) + var(--rhythm));
  z-index: 0;
  pointer-events: none;
}

.intro > :not(.intro__canvas) {
  position: relative;
  z-index: 2;
}

.intro__title,
.resume-heading__title {
  --reveal-x: 50%;
  --reveal-y: -65%;
  --reveal-radius: 0px;
  --reveal-feather: 0px;

  font-size: var(--step-3);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: 0.01em;
  color: var(--ink);

  /* Major-section links land on the rule that introduces the section, rather
     than cropping away the breathing room between that rule and its title. */
  scroll-margin-top: calc(var(--rhythm) + 1px);
}

.resume-heading {
  padding-top: var(--rhythm);
  border-top: 1px solid var(--rule);
}

.resume-heading__pdf {
  display: inline-flex;
  align-items: center;
  width: fit-content;
  margin-top: 0.8rem;
  padding: 0.55rem 0.8rem;
  border: 1px solid var(--ink);
  border-radius: 0.4rem;
  background: var(--ink);
  color: var(--ground);
  font-size: var(--step--1);
  text-decoration: none;
  transition:
    background 0.2s var(--ease),
    color 0.2s var(--ease);
}

.resume-heading__pdf:hover {
  background: transparent;
  color: var(--ink);
}

/* Echo the opening title reveal when About Me enters the viewport. The
   ready flag is JS-only, so the heading remains visible without scripting. */
.page[data-title-reveal-ready] .intro__title {
  -webkit-mask-image: radial-gradient(
    circle at var(--reveal-x) var(--reveal-y),
    #000 calc(var(--reveal-radius) - var(--reveal-feather)),
    transparent var(--reveal-radius)
  );
  mask-image: radial-gradient(
    circle at var(--reveal-x) var(--reveal-y),
    #000 calc(var(--reveal-radius) - var(--reveal-feather)),
    transparent var(--reveal-radius)
  );
}

.page[data-title-reveal-ready][data-title-reveal-complete] .intro__title {
  -webkit-mask-image: none;
  mask-image: none;
}

.intro__summary {
  max-width: var(--measure);
  font-size: var(--step-1);
  line-height: 1.62;
  color: rgba(var(--ink-rgb), 0.86);
}

.intro__summary-row {
  display: grid;
  grid-template-columns: minmax(0, var(--measure)) minmax(0, 1fr);
  align-items: center;
  width: 100%;
}

.facts {
  display: grid;
  gap: 0.3rem;
  margin-top: 0.4rem;
  /* The intro is `justify-items: start`, so without this the list shrink-wraps
     to its narrowest column and every value wraps onto two lines. */
  width: 100%;
  max-width: var(--measure);
}

.facts li {
  display: flex;
  gap: 0.9rem;
  align-items: baseline;
  font-size: var(--step--1);
}

.facts__k {
  flex: 0 0 4.5rem;
  font-size: var(--step--2);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-ghost);
}

.facts__v {
  color: var(--ink-dim);
}

/* A compact ECG-like ink trace is centred in the open column between the About
   Me paragraph and the section's right edge, and vertically centred on the
   paragraph. Its left edge fades in from the paper rather than starting at a
   hard crop. JavaScript changes its rate and excursion near the word "love";
   the canvas itself has no box, fill, label or interaction surface, so it
   reads as one drawn line. */
.intro__cardiograph {
  --cardiograph-overlap: clamp(0.5rem, 0.3rem + 0.4vw, 0.8rem);

  display: none;
  /* Once `.page` reaches its 68rem content cap, `50vw - 34rem` is the
     viewport-to-content gutter. Before then the page padding is that gutter.
     Reusing that distance keeps the trace compact within its open column. */
  inline-size: calc(
    max(var(--page-pad), calc(50vw - 34rem)) + var(--cardiograph-overlap)
  );
  block-size: clamp(3rem, 2.6rem + 1vw, 4rem);
  /* Explicit bounds stop a canvas's intrinsic bitmap dimensions from winning
     during Firefox's replaced-element sizing pass. */
  min-block-size: 3rem;
  max-block-size: 4rem;
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 42%);
  mask-image: linear-gradient(to right, transparent 0, #000 42%);
  pointer-events: none;
}

@media (min-width: 45rem) and (hover: hover) and (pointer: fine) {
  .intro__summary-row > .intro__cardiograph {
    display: block;
    grid-column: 2;
    place-self: center;
  }
}

/* Deterministic local capture hook. It never appears without an explicit
   query parameter, and does not alter the production desktop-only rule. */
:root[data-cardiograph-preview] .intro__summary-row > .intro__cardiograph {
  display: block;
  grid-column: 2;
  place-self: center;
}

/* ---- sections ---------------------------------------------------------- */

.rows-hint {
  font-size: var(--step--2);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-ghost);
  padding-top: 1.4rem;
  border-top: 1px solid var(--rule);
}

.section {
  display: grid;
  gap: clamp(0.9rem, 0.6rem + 0.8vw, 1.4rem);
}

/* The heading marker is a comment slash, not a word, so it lives in CSS: it
   must not land in the accessible name of the heading. */
.section__title {
  font-size: var(--step-2);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: 0.04em;
  color: var(--ink);
}

.section__title::before {
  content: '// ';
  color: var(--accent);
}

/* ---- entries ----------------------------------------------------------- */

.entries {
  display: grid;
  gap: clamp(0.8rem, 0.55rem + 0.9vw, 1.35rem);
}

.entry {
  overflow: hidden;
  border: 1px solid var(--rule);
  border-radius: clamp(1rem, 0.8rem + 0.8vw, 1.55rem);
  background: var(--ground);
}

.entry__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr) auto;
  align-items: baseline;
  gap: 0.35rem 1.5rem;
  width: 100%;
  text-align: left;
  padding: clamp(0.9rem, 1.1vw, 1.15rem) clamp(1rem, 1.1vw, 1.35rem);
}

.entry__head--wide {
  grid-template-columns: minmax(0, 1fr) auto;
}

.entry__org {
  font-size: var(--step-1);
}

.entry__identity {
  display: flex;
  align-items: flex-start;
  gap: clamp(0.65rem, 0.5rem + 0.35vw, 0.85rem);
  min-width: 0;
}

.entry__identity-copy {
  display: grid;
  gap: 0.15rem;
  min-width: 0;
}

.entry__logo {
  --entry-logo-size: clamp(2rem, 1.75rem + 0.8vw, 2.5rem);

  display: block;
  flex: 0 0 var(--entry-logo-size);
  width: var(--entry-logo-size);
  height: var(--entry-logo-size);
  min-width: var(--entry-logo-size);
  min-height: var(--entry-logo-size);
  max-width: var(--entry-logo-size);
  max-height: var(--entry-logo-size);
  object-fit: contain;
  border-radius: 0.45rem;
}

.entry__role {
  font-size: var(--step--1);
  color: var(--ink-dim);
}

.entry__when {
  font-size: var(--step--2);
  letter-spacing: 0.1em;
  color: var(--ink-ghost);
  white-space: nowrap;
  justify-self: end;
}

.entry__panel {
  display: flex;
  align-items: flex-start;
}

.entry__copy {
  flex: 1 1 auto;
  min-width: 0;
  align-self: start;
  padding: clamp(1.25rem, 1rem + 1.3vw, 2.15rem);
}

.entry__head--panel {
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  padding: clamp(0.9rem, 1.1vw, 1.15rem) clamp(1rem, 1.1vw, 1.35rem);
  border-bottom: 1px solid var(--rule);
}

.entry__head--panel .entry__when {
  grid-column: 2;
  grid-row: 1;
  color: var(--ink-dim);
}

.entry__detail {
  display: grid;
  grid-template-rows: 1fr;
}

.entry__inner {
  min-width: 0;
}

.entry:not(.entry--panel) .entry__inner {
  padding-inline: clamp(1rem, 1.1vw, 1.35rem);
}

.points {
  display: grid;
  gap: 0.55rem;
  max-width: var(--measure);
  padding-block: 1rem 1.25rem;
  color: rgba(var(--ink-rgb), 0.8);
}

.entry__inner .meta {
  padding-top: 1rem;
}

.entry--panel .points {
  max-width: none;
  padding-bottom: 0;
}

.points li {
  position: relative;
  padding-left: 1.1rem;
  font-size: var(--step-0);
  line-height: 1.55;
}

/* A hairline rule was the right marker for a typeset page. On a fixed pitch a
   hyphen sits exactly one column in and needs no measuring. */
.points li::before {
  content: '-';
  position: absolute;
  left: 0;
  color: var(--ink-ghost);
}

.points strong {
  font-weight: 400;
  color: var(--ink);
}

/* ---- image panels ------------------------------------------------------ */

.entry__media {
  display: flex;
  flex-direction: column;
  gap: clamp(0.35rem, 0.2rem + 0.35vw, 0.6rem);
  flex: 0 0 clamp(10rem, 17vw, 15rem);
  align-self: start;
  min-width: 0;
  height: clamp(13rem, 22vw, 18rem);
  padding: clamp(0.75rem, 0.55rem + 0.7vw, 1.1rem);
  transition: flex-basis 0.45s var(--ease-out);
}

.entry__image-panel {
  position: relative;
  display: block;
  flex: 1 1 0;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  border: 1px solid var(--rule);
  border-radius: clamp(0.75rem, 0.6rem + 0.5vw, 1.1rem);
  background: var(--ground-raised);
  transition: flex-grow 0.45s var(--ease-out), border-color 0.3s var(--ease);
}

.entry__media:hover,
.entry__media:focus-within {
  flex-basis: clamp(16rem, 32%, 22rem);
}

.entry__image-panel:hover,
.entry__image-panel:focus-visible,
.entry__image-panel:focus-within {
  flex-grow: 4;
  border-color: var(--rule-strong);
}

.entry__image-panel img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.entry__image-panel:nth-child(1) img {
  object-position: 16% 25%;
}

.entry__image-panel:nth-child(2) img {
  object-position: 50% center;
}

.entry__image-panel:nth-child(3) img {
  object-position: 84% 75%;
}

.entry__image-label {
  position: absolute;
  inset: auto 0 0;
  padding: 0.45rem 0.6rem;
  overflow: hidden;
  background: color-mix(in srgb, var(--ground) 76%, transparent);
  color: var(--ink);
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  line-height: 1.35;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(100%);
  backdrop-filter: blur(6px);
  transition: opacity 0.25s var(--ease), transform 0.3s var(--ease-out);
}

.entry__image-panel:hover .entry__image-label,
.entry__image-panel:focus-visible .entry__image-label,
.entry__image-panel:focus-within .entry__image-label {
  opacity: 1;
  transform: translateY(0);
}

.entry__bookmark {
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  width: 100%;
  height: 100%;
  color: inherit;
  text-decoration: none;
}

.entry__image-panel--bookmark .entry__bookmark .entry__bookmark-logo {
  align-self: center;
  justify-self: center;
  width: clamp(4rem, 45%, 7rem);
  height: auto;
  object-fit: contain;
  object-position: center;
}

.entry__bookmark-copy {
  display: grid;
  gap: 0.25rem;
  padding: clamp(0.7rem, 1.5vw, 1rem);
  border-top: 1px solid var(--rule);
  background: color-mix(in srgb, var(--ground) 76%, transparent);
  backdrop-filter: blur(6px);
}

.entry__bookmark-title,
.entry__bookmark-description,
.entry__bookmark-url {
  display: block;
}

.entry__bookmark-title {
  color: var(--ink);
  font-size: var(--step--1);
}

.entry__bookmark-description {
  color: var(--ink-faint);
  font-size: var(--step--2);
  line-height: 1.4;
}

.entry__bookmark-url {
  margin-top: 0.2rem;
  overflow: hidden;
  color: var(--ink-dim);
  font-size: var(--step--2);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.entry__bookmark:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: -3px;
}

/* ---- chips ------------------------------------------------------------- */

.groups {
  display: grid;
  gap: clamp(1.1rem, 2vw, 1.75rem);
}

.group__label {
  font-size: var(--step--2);
  letter-spacing: 0.14em;
  color: var(--ink-ghost);
  margin-bottom: 0.6rem;
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin-bottom: 0.6rem;
}

/* Brackets rather than a filled pill: on a fixed pitch the bracket is already
   a column wide, and a row of them reads as a token list. The border is the
   one thing left that carries the proficiency scale, so nothing else may draw
   a box — a fill under every chip would make all three grades look outlined. */
.chip {
  padding: 0.24rem 0.6rem;
  border: 1px solid transparent;
  border-radius: 2px;
  font-size: var(--step--1);
  color: var(--ink-dim);
  transition: background 0.25s var(--ease), color 0.25s var(--ease);
}

.chip::before {
  content: '[';
}

.chip::after {
  content: ']';
}

.chip::before,
.chip::after {
  color: var(--ink-ghost);
}

.chip:hover {
  background: var(--ground-raised-2);
  color: var(--ink);
}

.chip--experienced {
  border-color: var(--rule);
  color: rgba(var(--ink-rgb), 0.78);
}

.chip--proficient {
  border-color: var(--rule-strong);
  color: var(--ink);
}

/* ---- notes and footer -------------------------------------------------- */

.notes {
  display: grid;
  gap: 0.6rem;
  max-width: var(--measure);
  color: rgba(var(--ink-rgb), 0.8);
}

.notes li {
  position: relative;
  padding-left: 1.1rem;
}

.notes li::before {
  content: '-';
  position: absolute;
  left: 0;
  color: var(--ink-ghost);
}

.notes-note {
  color: var(--ink-faint);
}

.footer {
  display: grid;
  gap: 0.35rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
  color: var(--ink-faint);
  font-size: var(--step--1);
}

/* ---- narrow ------------------------------------------------------------ */

@media (max-width: 44rem) {
  .entry__panel {
    display: grid;
    grid-template-columns: 1fr;
    min-height: 0;
  }

  .entry__media,
  .entry__media:hover,
  .entry__media:focus-within {
    width: min(100%, 24rem);
    height: clamp(14rem, 62vw, 20rem);
    justify-self: end;
    padding-top: 0;
  }
}

@media (max-width: 44rem) {
  .entry__head,
  .entry__head--wide {
    grid-template-columns: 1fr;
    gap: 0.2rem;
  }

  .entry__when {
    justify-self: start;
  }

  .entry__head--panel .entry__when {
    grid-column: 1;
    grid-row: auto;
  }
}

/* ---- print: ink on paper ----------------------------------------------- */

@media print {
  :root {
    --ground: #fff;
    --ink-rgb: 20, 18, 15;
  }

  .grain,
  .rows-hint,
  .intro__cardiograph {
    display: none !important;
  }

  .page {
    border-top: 0;
    padding-top: 0;
  }

  .entry__inner {
    overflow: visible;
  }

  .entry,
  .entry__panel {
    break-inside: avoid;
  }

  .entry__panel {
    display: block;
    min-height: 0;
  }

  .entry__media {
    display: none;
  }
}
