/* =====================================================================
   Open roles — one record per row.

   A blueprint-style list: mono micro-labels, hairline rules, a single
   rust accent, and the whole row as the click target. Hovering draws a
   frame in from the left; arriving on scroll rises the parts of the row
   in sequence.

   NOTHING HERE HIDES ANYTHING BY ITSELF. The rules that start a row's
   parts invisible are scoped to .js-roles, which include/roles.js adds
   only once it has decided it is going to run. With JavaScript off, or
   with reduced motion on, the class never lands and every role is
   simply listed.
   ===================================================================== */

.roles{
  --role-in:  cubic-bezier(.2,.8,.25,1);
  --role-out: cubic-bezier(.4,0,1,1);
  border-top: 1px solid var(--line);
  margin-top: 8px;
}

.role{
  position: relative;
  display: grid;
  grid-template-columns: 108px minmax(0, 1fr) 168px 44px;
  gap: 0 28px;
  align-items: start;
  padding: 26px 20px 28px;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
  color: inherit;
  background: transparent;
  transition: background 180ms var(--role-in);
}

/* ---- the frame ------------------------------------------------------
   Drawn in from the left on arrival and retracted the way it came.

   The timing is deliberately asymmetric, and the two halves live in
   different rules: the BASE rule owns the leave, the hover rule owns
   the arrival. A slow retract would leave the old frame still unwinding
   underneath the row you have already moved onto, which reads as lag
   rather than as precision. */
.role .frame{
  position: absolute;
  inset: 0;
  border: 1.5px solid var(--accent);
  pointer-events: none;
  clip-path: inset(0 100% 0 0);
  transition: clip-path 150ms var(--role-out);
}
.role:hover .frame,
.role.hot .frame,
.role:focus-visible .frame{
  clip-path: inset(0 0 0 0);
  transition: clip-path 280ms var(--role-in);
}
.role:focus-visible{ outline: none; }

/* ---- the parts ------------------------------------------------------ */

.role__meta{
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-3);
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-start;
  padding-top: 5px;
}
.role__tag{
  border: 1px solid var(--accent-line);
  color: var(--accent);
  padding: 2px 7px;
  border-radius: 2px;
  transition: background 180ms var(--role-in), color 180ms var(--role-in),
              border-color 180ms var(--role-in);
}
.role__title{
  margin: 0 0 10px;
  font-size: clamp(19px, 1.9vw, 24px);
  font-weight: 400;
  letter-spacing: -.018em;
  line-height: 1.25;
  color: var(--text);
  transition: transform 180ms var(--role-in);
}
.role__blurb{
  margin: 0 0 14px;
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--text-2);
  max-width: 62ch;
}
.role__chips{
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.role__chips span{
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: .08em;
  color: var(--text-3);
  border: 1px solid var(--line);
  padding: 3px 7px;
  border-radius: 2px;
  transition: border-color 180ms var(--role-in);
}
.role__where{
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-3);
  line-height: 1.9;
  padding-top: 5px;
}
.role__go{
  justify-self: end;
  padding-top: 2px;
  font-size: 19px;
  line-height: 1;
  color: var(--text-3);
  transition: transform 180ms var(--role-in), color 180ms var(--role-in);
}

/* ---- selected -------------------------------------------------------
   .hot is set by roles.js while a scroll moves a row under a stationary
   pointer; :focus-visible covers the keyboard. All three states must
   answer identically or the row behaves differently depending on how
   you reached it. Nothing scales, nothing else dims. */
.role:hover,
.role.hot,
.role:focus-visible{ background: var(--bg-hi, #FFFFFF); }

.role:hover .role__title,
.role.hot .role__title,
.role:focus-visible .role__title{ transform: translate3d(4px, 0, 0); }

.role:hover .role__go,
.role.hot .role__go,
.role:focus-visible .role__go{
  transform: translate3d(5px, 0, 0);
  color: var(--accent);
}
.role:hover .role__tag,
.role.hot .role__tag,
.role:focus-visible .role__tag{
  background: var(--accent);
  border-color: var(--accent);
  color: #F7F4F1;
}
.role:hover .role__chips span,
.role.hot .role__chips span,
.role:focus-visible .role__chips span{ border-color: var(--accent-line); }

/* ---- arrival --------------------------------------------------------- */

.js-roles .role__meta,
.js-roles .role__title,
.js-roles .role__where,
.js-roles .role__blurb,
.js-roles .role__chips,
.js-roles .role__go{ opacity: 0; }

.js-roles .role.on .role__meta  { animation: role-rise 460ms var(--role-in)  40ms forwards; }
.js-roles .role.on .role__title { animation: role-rise 460ms var(--role-in) 110ms forwards; }
.js-roles .role.on .role__where { animation: role-rise 460ms var(--role-in) 150ms forwards; }
.js-roles .role.on .role__blurb { animation: role-rise 460ms var(--role-in) 180ms forwards; }
.js-roles .role.on .role__chips { animation: role-rise 460ms var(--role-in) 240ms forwards; }
.js-roles .role.on .role__go    { animation: role-rise 460ms var(--role-in) 300ms forwards; }

@keyframes role-rise{
  from{ opacity: 0; transform: translate3d(0, 7px, 0); }
  to  { opacity: 1; transform: none; }
}

/* THE ONE THAT BITES.

   animation-fill-mode: forwards keeps ownership of transform after the
   animation has finished, and a finished animation still outranks a
   plain declaration. So on every row that had already arrived, the
   hover nudge silently did nothing: the rule applied, the animation
   just kept winning.

   roles.js adds .done once the sequence is over. This hands transform
   back by killing the animation outright, then re-declares the hover
   transforms at a specificity that beats the arrival rules. */
.js-roles .role.done .role__meta,
.js-roles .role.done .role__title,
.js-roles .role.done .role__where,
.js-roles .role.done .role__blurb,
.js-roles .role.done .role__chips,
.js-roles .role.done .role__go{
  animation: none;
  opacity: 1;
  transform: none;
}
.js-roles .role.done:hover .role__title,
.js-roles .role.done.hot .role__title,
.js-roles .role.done:focus-visible .role__title{ transform: translate3d(4px, 0, 0); }

.js-roles .role.done:hover .role__go,
.js-roles .role.done.hot .role__go,
.js-roles .role.done:focus-visible .role__go{ transform: translate3d(5px, 0, 0); }

@media (max-width: 900px){
  .role{
    grid-template-columns: 92px minmax(0, 1fr) 36px;
    gap: 0 18px;
  }
  .role__where{
    grid-column: 2;
    padding-top: 12px;
  }
}
@media (max-width: 620px){
  .role{ grid-template-columns: 1fr; gap: 12px; padding: 22px 14px 24px; }
  .role__meta{ flex-direction: row; align-items: center; gap: 12px; }
  .role__go{ justify-self: start; }
}

/* Belt and braces: roles.js declines to add .js-roles under reduced
   motion, so these should never be needed. Everything visible, no
   transitions, no transforms. */
@media (prefers-reduced-motion: reduce){
  .js-roles .role__meta,
  .js-roles .role__title,
  .js-roles .role__where,
  .js-roles .role__blurb,
  .js-roles .role__chips,
  .js-roles .role__go{ opacity: 1; animation: none; transform: none; }
  .role, .role *, .role .frame{ transition: none; }
  .role .frame{ clip-path: inset(0 0 0 0); border-color: transparent; }
  .role:hover .frame, .role.hot .frame{ border-color: var(--accent); }
}
