/* ============================================================
   Pre-registration · /join
   Tokens come from marketing/tokens.css. Nothing here defines a
   colour, a radius or an easing of its own.

   The Figma frames name their own token set, and the two disagree
   about one word: Figma's --ink is white and its --text is the
   near-black, while this project's --ink IS the near-black. The
   project's names win everywhere below.
   ============================================================ */

/* The reset, the body defaults, the type scale and the buttons come from
   marketing/base.css. Only what this page adds is below. */
body.join{min-height:100vh;}

/* Desktop: the form on the left, the directory on the right. The Figma puts
   the form at x=120 in a 560-wide column and the rail from x=800 to 1440 —
   a 55.5/44.5 split, expressed as a fraction so it survives a wider window. */
@media (min-width:1000px){
  body.join{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,640px);}
}

.join-form{padding:56px 24px 80px;max-width:680px;width:100%;}
@media (min-width:1000px){.join-form{padding:56px 64px 80px 120px;}}

/* The mark is ink here, not primary: the join screens put it on a light ground
   with nothing else at the top, so it reads as the wordmark rather than as a
   link. `a{color:var(--primary)}` in base.css would otherwise colour it. */
.join-brand{display:block;width:52px;height:30px;margin-bottom:60px;color:var(--ink);}
.join-brand svg{width:100%;height:100%;display:block;}

/* ---------- the step indicator: four segments, never seven ---------- */
.join-steps{display:flex;gap:10px;margin:0 0 42px;padding:0;list-style:none;max-width:560px;}
.join-steps li{flex:1;height:4px;border-radius:var(--r-pill);background:var(--line);}
.join-steps li.on{background:var(--primary);}

.join-eyebrow{color:var(--faint);margin:0 0 12px;}
/* An eyebrow that follows an answered question opens a new one, and needs the
   air to say so — the note under the circuits used to sit against the next
   heading. */
.join-note + .join-eyebrow,
.join-chips + .join-eyebrow{margin-top:34px;}

/* 620, not the 560 every other block uses: the Figma holds "Get in line for
   Tennis Network" on one line at 44px, and Google's Archivo sets a little wider
   than the variable font the file is drawn with. Narrower here breaks the line
   and the whole top-left block reads differently. */
.join-title{
  font-family:Archivo,sans-serif;font-weight:600;
  font-size:clamp(32px,4.4vw,44px);line-height:1.045;letter-spacing:-.035em;
  margin:0 0 16px;max-width:620px;text-wrap:balance;
}
.join-lede{color:var(--muted);margin:0 0 34px;max-width:560px;}

/* ---------- fields ---------- */
.join-field{max-width:560px;margin:0 0 20px;}
.join-field label{display:block;margin-bottom:9px;}
.join-field input[type="email"],
.join-field input[type="month"],
.join-field input[type="text"]{
  width:100%;padding:15px;font:inherit;font-size:15px;line-height:22px;
  color:var(--ink);background:var(--bg);
  border:1.5px solid var(--line-strong);border-radius:var(--r-action);
  transition:border-color .18s var(--ease);
}
.join-field input::placeholder{color:var(--faint);}
.join-field input:focus{outline:none;border-color:var(--primary);}

.join-actions{max-width:560px;margin:0 0 14px;}
.join-actions .btn{width:100%;justify-content:center;padding:17px 25px;font-size:15.5px;line-height:19px;}
.join-actions .btn[disabled]{background:var(--disabled);border-color:var(--disabled);color:var(--faint);cursor:not-allowed;}

.join-note{color:var(--faint);margin:0;max-width:560px;}

.join-error{
  max-width:560px;margin:0 0 20px;padding:12px 14px;
  border:1px solid var(--line);border-left:3px solid var(--negative);
  border-radius:var(--r-field);color:var(--ink);background:var(--surface);
}

/* What the step just did. Same shape as an error, because it is the same kind
   of thing — a sentence the screen owes the member — and only the mark down
   the side says which. */
.join-flash{
  max-width:560px;margin:0 0 24px;padding:12px 14px;
  border:1px solid var(--line);border-radius:var(--r-field);
  color:var(--ink);background:var(--surface);
}
.join-flash.is-notice{border-left:3px solid var(--primary);}
.join-flash.is-alert{border-left:3px solid var(--negative);}

.join-links{max-width:560px;margin:18px 0 0;display:flex;gap:20px;flex-wrap:wrap;}
.join-links button,.join-links a{
  background:none;border:0;padding:0;font:inherit;font-weight:600;font-size:13px;
  color:var(--primary);cursor:pointer;text-decoration:none;
}
.join-links button:hover,.join-links a:hover{text-decoration:underline;}

/* ---------- the six boxes ----------
   Painted around one real input. The input itself is moved off-screen rather
   than hidden: it must stay focusable, and it is what carries paste, a password
   manager and iOS's one-time-code autofill. Without JS it is a plain field and
   the screen still works. */
.join-code-field{position:relative;max-width:560px;margin:0 0 20px;}
.join-code{display:flex;gap:10px;}
.join-code span{
  flex:1;min-width:0;aspect-ratio:1;display:flex;align-items:center;justify-content:center;
  font-family:Archivo,sans-serif;font-weight:600;font-size:26px;color:var(--ink);
  background:var(--bg);border:1.5px solid var(--line-strong);border-radius:var(--r-action);
  transition:border-color .18s var(--ease);
}
.join-code span.filled{border-color:var(--line-strong);}
.join-code span.cursor{border-color:var(--primary);}

/* Laid over the boxes at full size rather than hidden off to one side. An
   off-canvas focusable control makes the browser scroll the page sideways to
   reveal it on focus — which shifted the layout and left a horizontal
   scrollbar. Here focus lands exactly where the boxes already are, and a click
   on a box is a click on the input. */
input.join-code-input{
  position:absolute;inset:0;width:100%;height:100%;
  opacity:0;padding:0;margin:0;border:0;background:none;
  font:inherit;cursor:text;
}

/* The trap. Never display:none — a bot reads the computed style too. Clipped
   rather than parked at left:-9999px: off-canvas geometry is what made the code
   field scroll the page, and a focusable field out there would do the same. */
.join-trap{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;
}

/* ---------- the rail ---------- */
.join-rail{display:none;}
@media (min-width:1000px){
  .join-rail{
    display:block;position:sticky;top:0;overflow:hidden;
    background:var(--surface);height:100vh;
  }
  /* The fades are the whole illusion: the strip has no beginning and no end. */
  .join-rail::before,.join-rail::after{
    content:"";position:absolute;left:0;right:0;height:300px;z-index:2;pointer-events:none;
  }
  .join-rail::before{top:0;background:linear-gradient(180deg,var(--surface) 0%,var(--surface) 34%,rgba(244,246,250,0) 100%);}
  .join-rail::after{bottom:0;background:linear-gradient(0deg,var(--surface) 0%,rgba(244,246,250,0) 100%);}
}

/* ---------- the role grid ----------
   Two columns on desktop, stacked on mobile. That is the only structural
   difference between the breakpoints on this screen. */
.join-roles{display:grid;gap:12px;max-width:560px;margin:0 0 34px;}
@media (min-width:700px){.join-roles{grid-template-columns:1fr 1fr;}}

.join-role{
  position:relative;display:flex;align-items:flex-start;gap:12px;
  padding:16px 18px;cursor:pointer;
  background:var(--bg);border:1.5px solid var(--line);border-radius:var(--r-card);
  transition:border-color .18s var(--ease), background-color .18s var(--ease);
}
.join-role:hover{border-color:var(--line-strong);}
.join-role input{position:absolute;opacity:0;width:1px;height:1px;}
.join-role-body{display:flex;flex-direction:column;gap:3px;flex:1;min-width:0;}
.join-role-blurb{color:var(--muted);}

/* The tick is drawn, not an asset: it is a state of this control rather than an
   icon with a meaning of its own. */
.join-role-tick{
  flex:none;width:22px;height:22px;border-radius:50%;
  border:1.5px solid var(--line-strong);background:var(--bg);
  transition:border-color .18s var(--ease), background-color .18s var(--ease);
}
.join-role:has(input:checked){border-color:var(--primary);}
.join-role:has(input:checked) .join-role-tick{
  border-color:var(--primary);background:var(--primary);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
  background-size:14px;background-repeat:no-repeat;background-position:center;
}
.join-role:has(input:focus-visible){outline:2px solid var(--primary);outline-offset:2px;}

/* ---------- the ranking results ---------- */
.join-results{display:flex;flex-direction:column;margin:10px 0 0;
  border:1px solid var(--line);border-radius:var(--r-card);overflow:hidden;}
.join-results:empty{display:none;}
.join-result{
  display:grid;grid-template-columns:auto 1fr auto;gap:12px;align-items:center;
  padding:12px 16px;text-align:left;cursor:pointer;width:100%;
  background:var(--bg);border:0;border-bottom:1px solid var(--line);font:inherit;color:var(--ink);
}
.join-result:last-child{border-bottom:0;}
.join-result:hover{background:var(--surface);}
.join-result.on{background:var(--surface);}

.join-result-face{
  width:36px;height:36px;border-radius:var(--r-pill);flex:none;object-fit:cover;
  background:var(--night-100);
}
.join-result-face.is-initials{
  display:flex;align-items:center;justify-content:center;
  font-weight:600;font-size:13px;color:var(--avatar-initials);
}

.join-result-body{display:flex;flex-direction:column;gap:2px;min-width:0;}
.join-result-line{display:flex;align-items:baseline;gap:8px;min-width:0;}
.join-result-line .label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}

/* The country sits beside the name, not out at the right margin: it reads as
   part of who this is, and the right edge belongs to the choice. */
.join-result-country{
  flex:none;font-weight:600;font-size:11px;letter-spacing:.08em;color:var(--faint);
}
.join-result-rank{color:var(--muted);}

.join-result-tick{
  flex:none;width:22px;height:22px;border-radius:50%;
  border:1.5px solid var(--line-strong);background:var(--bg);
}
.join-result.on .join-result-tick{
  border-color:var(--primary);background:var(--primary);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
  background-size:14px;background-repeat:no-repeat;background-position:center;
}

/* ---------- the photo ----------
   The input covers the zone rather than sitting inside it, so the whole
   rectangle is the control — and it stays a real file input, so a browser with
   no drag-and-drop, and every phone, still opens the camera or the library. */
.join-drop{
  position:relative;max-width:560px;margin:0 0 34px;min-height:200px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;
  padding:28px;text-align:center;cursor:pointer;
  background:var(--surface);border:1.5px dashed var(--line-strong);border-radius:var(--r-module);
  transition:border-color .18s var(--ease), background-color .18s var(--ease);
}
.join-drop:hover,.join-drop.over{border-color:var(--primary);background:var(--primary-tint);}
.join-drop input[type="file"]{position:absolute;inset:0;opacity:0;cursor:pointer;}
.join-drop img{max-height:200px;border-radius:var(--r-card);}
.join-drop-browse{color:var(--primary);}

/* ---------- the circuit chips ----------
   chip/Filter, drawn here rather than borrowed from marketing.css — this
   surface does not load that stylesheet, which is why the chips arrived as
   bare text. The chevron is the component's own mark and is carried on both
   states; only its colour changes, so it is drawn in currentColor from two
   borders rather than fetched as an asset. */
.join-chips{display:flex;flex-wrap:wrap;gap:8px;max-width:560px;margin:0 0 10px;}
.join-chip{
  display:inline-flex;align-items:center;gap:8px;height:36px;padding:0 16px;
  position:relative;cursor:pointer;
  background:var(--bg);border:1px solid var(--line-strong);border-radius:var(--r-pill);
  font-family:Inter,sans-serif;font-weight:600;font-size:14px;line-height:17px;
  letter-spacing:-.012em;color:var(--ink);
}
.join-chip::before{
  content:"";flex:none;width:6px;height:6px;margin-top:-3px;
  border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  border-radius:0 0 1px 0;transform:rotate(45deg);
}
.join-chip input{position:absolute;opacity:0;width:1px;height:1px;}
.join-chip:has(input:checked){background:var(--primary);border-color:var(--primary);color:var(--on-primary);}
.join-chip:has(input:focus-visible){outline:2px solid var(--primary);outline-offset:2px;}

/* ---------- the players ----------
   A settled answer, not a fieldset. The claim is made in the dialog and the
   row is what it left behind: face, name, whether it is current, and the span
   of it. The fields the form posts are hidden inside the row, so removing one
   removes its answer with it. */
.join-players{display:flex;flex-direction:column;gap:10px;max-width:560px;margin:0 0 10px;}
.join-players:empty{display:none;}
.join-player{
  display:flex;align-items:center;gap:14px;padding:12px 16px;
  background:var(--bg);border:1px solid var(--line);border-radius:var(--r-action);
}
.join-player-face{
  flex:none;width:44px;height:44px;border-radius:50%;object-fit:cover;
  background:var(--surface);
}
span.join-player-face{
  display:grid;place-items:center;
  font-family:"Chivo Mono",monospace;font-size:13px;font-weight:600;color:var(--faint);
}
.join-player-body{display:flex;flex-direction:column;gap:3px;flex:1;min-width:0;}
.join-player-line{display:flex;align-items:center;gap:8px;min-width:0;}
.join-player-name{
  font-family:Archivo,sans-serif;font-weight:600;font-size:17px;line-height:21px;
  letter-spacing:-.022em;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.join-player-tag{
  flex:none;padding:5px 10px;background:var(--surface);border-radius:var(--r-field);
  font-family:Inter,sans-serif;font-weight:600;font-size:12.5px;line-height:15px;
  letter-spacing:-.005em;color:var(--ink);
}
.join-player-dates{margin:0;font-size:12.5px;line-height:18px;color:var(--muted);}
.join-player-remove{
  flex:none;width:18px;height:18px;padding:0;background:none;border:0;cursor:pointer;
  position:relative;color:var(--faint);
}
.join-player-remove::before,.join-player-remove::after{
  content:"";position:absolute;left:1px;right:1px;top:8px;height:2px;border-radius:1px;
  background:currentColor;
}
.join-player-remove::before{transform:rotate(45deg);}
.join-player-remove::after{transform:rotate(-45deg);}
.join-player-remove:hover{color:var(--negative);}

/* row/AddDashed */
.join-add{
  display:flex;align-items:center;justify-content:center;
  width:100%;max-width:560px;height:46px;margin:0 0 34px;padding:0;
  font-family:Inter,sans-serif;font-weight:600;font-size:14px;letter-spacing:-.012em;
  color:var(--ink);cursor:pointer;
  background:none;border:1px dashed var(--line-strong);border-radius:var(--r-action);
}
.join-add:hover{border-color:var(--primary);color:var(--primary);}

/* ---------- the add-a-player dialog ----------
   Two panes and one dialog: finding the player, then saying when. They are the
   same claim, so they are the same surface — going back is going back a pane,
   not losing the answer. */
.join-modal{
  width:min(480px,calc(100vw - 32px));padding:0;
  background:var(--bg);border:0;border-radius:var(--r-module);
  box-shadow:0 24px 60px rgba(18,24,40,.18);
}
.join-modal::backdrop{background:rgba(18,24,40,.42);}
/* The month picker's popover has to be able to leave the dialog; the dialog's
   own content is bounded by the capped results list, so nothing else needs the
   scroller the user agent gives it. */
.join-modal{overflow:visible;}
.join-modal-head{display:flex;align-items:center;gap:12px;padding:22px 26px 0;}
.join-modal-title{
  flex:1;margin:0;font-family:Archivo,sans-serif;font-weight:700;font-size:20px;
  line-height:24px;letter-spacing:-.022em;color:var(--ink);
}
.join-modal-close{
  flex:none;width:22px;height:22px;padding:0;background:none;border:0;cursor:pointer;
  position:relative;color:var(--muted);
}
.join-modal-close::before,.join-modal-close::after{
  content:"";position:absolute;left:2px;right:2px;top:10px;height:2px;border-radius:1px;
  background:currentColor;
}
.join-modal-close::before{transform:rotate(45deg);}
.join-modal-close::after{transform:rotate(-45deg);}
.join-modal-body{padding:18px 26px 26px;}
.join-modal-hint{margin:8px 0 0;font-size:12.5px;line-height:18px;color:var(--muted);}
.join-modal-wrong{margin:8px 0 0;color:var(--negative);}
.join-modal .join-results{max-height:330px;overflow-y:auto;}

.join-modal-label{display:block;margin:20px 0 8px;}
/* The magnifier the design puts in the field, drawn rather than fetched: a
   ring and a handle, which is all it is. */
.join-modal-find{position:relative;}
.join-modal-find input{padding-left:46px;}
.join-modal-find::before{
  content:"";position:absolute;left:18px;top:50%;width:11px;height:11px;
  margin-top:-7px;border:1.7px solid var(--faint);border-radius:50%;pointer-events:none;
}
.join-modal-find::after{
  content:"";position:absolute;left:28px;top:50%;width:5px;height:1.7px;
  margin-top:4px;background:var(--faint);border-radius:1px;
  transform:rotate(45deg);transform-origin:left center;pointer-events:none;
}
.join-modal .join-actions{margin:22px 0 0;}
.join-modal .btn{width:100%;margin:0;}
.join-modal .join-field,.join-modal .join-month{margin:0;}
/* The initials stand in for a face the roster has none of, in both panes. */
.join-result-face.is-initials,.join-player-face.is-initials{
  display:grid;place-items:center;background:var(--surface);
  font-family:"Chivo Mono",monospace;font-size:13px;font-weight:600;color:var(--faint);
}

/* The chosen player, at the top of the second pane — a row that goes back. */
.join-chosen{
  display:flex;align-items:center;gap:14px;width:100%;padding:12px 16px;
  font:inherit;text-align:left;cursor:pointer;
  background:var(--bg);border:1px solid var(--line);border-radius:var(--r-action);
}
.join-chosen::after{
  content:"";flex:none;width:7px;height:7px;
  border-top:2px solid var(--faint);border-right:2px solid var(--faint);
  border-radius:0 1px 0 0;transform:rotate(45deg);
}
.join-chosen:hover{border-color:var(--line-strong);}
.join-chosen .join-result-body{flex:1;}

/* ---------- the month picker ----------
   A month, picked as a month. The browser's own control is a date field in
   disguise — a masked "----" to type into, and a popover belonging to the
   browser rather than to this design. */
.join-month{position:relative;max-width:560px;margin:0 0 20px;}
.join-month-field{
  display:flex;align-items:center;gap:12px;width:100%;padding:15px;
  font:inherit;font-size:15px;line-height:22px;text-align:left;cursor:pointer;
  color:var(--ink);background:var(--bg);
  border:1.5px solid var(--line-strong);border-radius:var(--r-action);
  transition:border-color .18s var(--ease);
}
.join-month-field:hover{border-color:var(--line-on-ground);}
.join-month-field:focus-visible{outline:none;border-color:var(--primary);}
.join-month-text{flex:1;min-width:0;}
.join-month.is-empty .join-month-text{color:var(--faint);}
.join-month-field::after{
  content:"";flex:none;width:7px;height:7px;margin-top:-4px;
  border-right:2px solid var(--faint);border-bottom:2px solid var(--faint);
  border-radius:0 0 1px 0;transform:rotate(45deg);
}
/* Drawn rather than fetched, like every other mark on this surface. */
.join-month-mark{
  position:relative;flex:none;width:17px;height:16px;
  border:1.6px solid var(--faint);border-radius:4px;
  box-shadow:inset 0 3.4px 0 var(--faint);
}
.join-month-mark::before,.join-month-mark::after{
  content:"";position:absolute;top:-3px;width:1.6px;height:3.4px;
  background:var(--faint);border-radius:1px;
}
.join-month-mark::before{left:3px;}
.join-month-mark::after{right:3px;}

.join-month-pop{
  position:absolute;z-index:5;top:calc(100% + 8px);left:0;width:min(300px,100%);
  padding:14px;background:var(--bg);
  border:1px solid var(--line);border-radius:var(--r-action);
  box-shadow:0 18px 40px rgba(18,24,40,.16);
}
.join-month-pop.is-up{top:auto;bottom:calc(100% + 8px);}
.join-month-head{display:flex;align-items:center;justify-content:space-between;margin:0 0 12px;}
.join-month-year{
  font-family:"Chivo Mono",monospace;font-weight:600;font-size:14px;
  letter-spacing:.06em;color:var(--ink);
}
.join-month-step{
  position:relative;width:28px;height:28px;padding:0;cursor:pointer;
  background:none;border:0;border-radius:var(--r-field);color:var(--muted);
}
.join-month-step:hover{background:var(--surface);color:var(--ink);}
.join-month-step:focus-visible,.join-month-cell:focus-visible{
  outline:2px solid var(--primary);outline-offset:1px;
}
.join-month-step::before{
  content:"";position:absolute;left:50%;top:50%;width:7px;height:7px;
  border-top:2px solid currentColor;border-right:2px solid currentColor;border-radius:0 1px 0 0;
}
.join-month-step.is-next::before{transform:translate(-70%,-50%) rotate(45deg);}
.join-month-step.is-back::before{transform:translate(-30%,-50%) rotate(-135deg);}

.join-month-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;}
.join-month-cell{
  height:36px;padding:0;cursor:pointer;
  background:none;border:0;border-radius:var(--r-field);
  font-family:Inter,sans-serif;font-weight:600;font-size:13px;color:var(--ink);
}
.join-month-cell:hover{background:var(--surface);}
.join-month-cell.on{background:var(--primary);color:var(--on-primary);}

/* "Currently working together" — the answer that decides whether an end date
   is asked at all, which is why it is a switch and not a second date field. */
.join-switch{
  display:flex;align-items:center;gap:16px;margin:12px 0 0;padding:14px 16px;
  background:var(--surface);border-radius:var(--r-action);cursor:pointer;
}
.join-switch-body{flex:1;min-width:0;}
.join-switch-body .label{display:block;}
.join-switch-body .body-s{margin:2px 0 0;color:var(--muted);}
.join-switch input{position:absolute;opacity:0;width:1px;height:1px;}
.join-switch-track{
  flex:none;width:52px;height:31px;border-radius:var(--r-pill);
  background:var(--line-strong);transition:background .18s ease;position:relative;
}
.join-switch-track::after{
  content:"";position:absolute;top:3px;left:3px;width:25px;height:25px;border-radius:50%;
  background:var(--bg);transition:transform .18s ease;
}
.join-switch:has(input:checked) .join-switch-track{background:var(--primary);}
.join-switch:has(input:checked) .join-switch-track::after{transform:translateX(21px);}
.join-switch:has(input:focus-visible) .join-switch-track{outline:2px solid var(--primary);outline-offset:2px;}
.join-add:hover{border-color:var(--primary);color:var(--primary);}

/* ---------- the screens after the form ---------- */
.join-list{max-width:560px;margin:0 0 34px;padding:0;list-style:none;}
.join-list li{
  position:relative;padding:0 0 0 26px;margin:0 0 12px;color:var(--muted);
}
.join-list li::before{
  content:"";position:absolute;left:0;top:8px;width:7px;height:7px;
  border-radius:50%;background:var(--primary);
}
.join-spacer{margin-top:8px;}

/* ---------- card/Directory ----------
   The component is fixed geometry, not a flexible grid: four blocks of exact
   heights — band 64, identity 150, record 128, offer 90 — with everything
   placed at absolute offsets inside them. 64+150+128+90 = 432, which is what
   the "everything on" state measures, and identity+record = 278, which is what
   the four bare cards on P1a measure. Reproducing it any other way is why an
   earlier version of this file looked approximately right and matched nothing.

   Chivo Mono is loaded for this card alone: the record is a receipt, and the
   monospace is what makes the leaders line up and the values sit in a column. */

/* `1fr auto 1fr`: the two staged groups take equal space and the middle row is
   the visitor's card, so it sits dead centre of the panel however many cards
   are above or below it. Matching the counts either side would centre it too,
   but that makes the number of staged cards load-bearing — change one and the
   card drifts. The strip is taller than the panel on purpose; the fades cover
   the cut. */
.join-rail-strip{
  display:grid;grid-template-rows:minmax(0,1fr) auto minmax(0,1fr);row-gap:22px;
  justify-items:center;height:100%;
}
.join-rail-group{display:flex;flex-direction:column;gap:22px;}
/* Each group grows away from the card, so the cards nearest it are the ones
   that stay on screen. */
.join-rail-group.is-above{align-self:end;}
.join-rail-group.is-below{align-self:start;}

.join-card{
  width:342px;flex:none;overflow:hidden;position:relative;
  background:var(--bg);border:1px solid var(--line);border-radius:20px;
  box-shadow:0 10px 26px -6px rgba(13,18,38,.08);
  opacity:.85;
}

/* 1.18, because that is what P1a does: the others are instances at 342x278 and
   the visitor's own is the same component at 403.56x509.76 — the whole card
   scaled, not a wider one with the same type. `zoom` rather than `transform` so
   the scaled card still takes its real height and the 22px gaps stay 22px. */
.join-card.is-mine{zoom:1.18;opacity:1;}

.join-rail-strip:has(> :nth-child(4)) .join-card:not(.is-mine):first-child,
.join-rail-strip:has(> :nth-child(4)) .join-card:not(.is-mine):last-child{opacity:.5;}

/* ---- the tournament band · 64 ---- */
.join-card-band{position:relative;height:64px;background:var(--primary);}
.join-card-band .join-card-kicker{position:absolute;left:20px;top:18px;width:195px;color:rgba(255,255,255,.6);}
.join-card-tour{
  position:absolute;left:20px;top:32px;width:195px;margin:0;
  font-family:"Chivo Mono",ui-monospace,monospace;font-size:13px;line-height:19px;color:var(--night-0);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}

/* Single line, always. The component sizes each of these boxes to the exact
   string it ships with; a real one a few characters longer wrapped onto the
   line below and sat on top of it. Truncating is the honest failure here — the
   kicker is context, and the headline underneath is the point. */
.join-card-kicker{
  margin:0;font-family:"Chivo Mono",ui-monospace,monospace;
  font-weight:600;font-size:9px;line-height:12px;letter-spacing:1.08px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}

/* The rung of the ladder, at the band's right. Two lines: a small tracked
   kicker over the name of the tier. */
.join-card-tier{
  position:absolute;right:20px;top:9px;width:46px;margin:0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;color:var(--night-0);
}
.join-card-tier span:first-child{
  font-family:Inter,sans-serif;font-weight:600;font-size:7.5px;line-height:1.3;
  letter-spacing:.75px;opacity:.7;
}
.join-card-tier span:last-child{
  font-family:Archivo,sans-serif;font-weight:600;font-size:12.5px;line-height:1.18;
  letter-spacing:-.125px;
}

/* ---- identity · 150 ---- */
.join-card-identity{position:relative;height:150px;}

.join-card-slot{
  position:absolute;left:20px;top:24px;width:76px;height:92px;
  border-radius:6px;overflow:hidden;
  background:linear-gradient(129.56deg,#1e2639 0%,#060914 100%);
}
/* Drawn as a doubled outline in royal on the ground colour, never filled in a
   circle — the component says so in as many words. Transparent text carrying
   three glows is what draws it. */
.join-card-initials{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  transform:rotate(-22deg);
  font-family:Archivo,sans-serif;font-weight:600;font-size:62.2px;line-height:1;
  color:transparent;white-space:nowrap;
  /* An outline, not a glow. The component's own words are "a doubled outline in
     royal/900" — Figma's three shadows read as a thin double line there, but
     three CSS text-shadows at 62px stack into a solid blob. A text-stroke is
     what actually draws the thing the component describes. */
  -webkit-text-stroke:1px rgba(92,120,255,.55);
  text-shadow:0 0 9px rgba(92,120,255,.14);
}
.join-card-photo{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  border:1px solid var(--line);
}

.join-card-role{
  position:absolute;left:108px;top:26px;width:162px;margin:0;
  font-family:"Chivo Mono",ui-monospace,monospace;
  font-weight:600;font-size:9px;line-height:12px;letter-spacing:1.08px;color:var(--primary);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.join-card-country{
  position:absolute;left:278px;top:24px;margin:0;display:flex;align-items:center;gap:6px;
  font-family:"Chivo Mono",ui-monospace,monospace;
  font-size:9px;line-height:12px;letter-spacing:.54px;color:var(--muted);
}
/* Sized against the code beside it: an emoji flag renders large and would
   outweigh the line it sits on. */
.join-card-flag{font-size:12px;line-height:13px;}

.join-card-name{
  position:absolute;left:108px;top:42px;width:214px;margin:0;
  font-family:Archivo,sans-serif;font-weight:600;font-size:28px;line-height:29px;
  letter-spacing:-.896px;color:var(--ink);text-transform:uppercase;
  /* A long single surname — Gardenborough, Auger-Aliassime — is wider than the
     214 the design allots it. Wrapping inside the box beats being clipped at
     the card edge, which is what `overflow:hidden` would otherwise do to it. */
  overflow-wrap:anywhere;
}

.join-card-availability{
  position:absolute;left:108px;top:106px;width:214px;margin:0;
  display:flex;align-items:center;gap:8px;
  font-family:"Chivo Mono",ui-monospace,monospace;
  font-size:9px;line-height:12px;letter-spacing:.54px;
}
.join-card-availability.is-available{color:var(--available);}
.join-card-availability.is-partial{color:var(--pending);}
.join-card-dot{width:7px;height:7px;border-radius:3.5px;background:currentColor;flex:none;}

/* ---- the record · 128 ----
   Hairlines at the top of the block and 106 down it; the rows sit between. */
.join-card-record{
  position:relative;height:128px;margin:0;padding:0;
}
.join-card-record::before,.join-card-record::after{
  content:"";position:absolute;left:20px;width:302px;height:1px;background:var(--line);
}
.join-card-record::before{top:0;}
.join-card-record::after{top:106px;}

.join-card-rows{
  position:absolute;left:20px;top:18px;width:302px;
  display:flex;flex-direction:column;gap:7px;
}
.join-card-row{display:flex;align-items:flex-start;gap:12px;height:19px;}
.join-card-row dt,.join-card-row dd{
  margin:0;font-family:"Chivo Mono",ui-monospace,monospace;
  font-size:13px;line-height:19px;white-space:nowrap;flex:none;
}
.join-card-row dt{color:var(--muted);}
.join-card-row dd{font-weight:600;color:var(--ink);text-align:right;}
/* The leader fills whatever the two ends leave, and its rule sits on the
   baseline rather than under the row. */
.join-card-leader{flex:1 0 0;min-width:0;height:19px;position:relative;}
.join-card-leader::after{
  content:"";position:absolute;left:0;right:0;top:12px;border-bottom:1px dashed var(--faint);
}

/* ---- the offer · 90 ---- */
.join-card-offer{position:relative;height:90px;}
.join-card-square{
  position:absolute;left:20px;top:2px;width:8px;height:8px;border-radius:1px;background:var(--ochre);
}
/* 200 rather than the component's 155: the stamp starts at 258, so there is
   room, and 155 clipped "OPPORTUNITY · 2 DAYS AGO" one character short. */
.join-card-offer .join-card-kicker{position:absolute;left:36px;top:0;width:200px;color:var(--faint);}
.join-card-offer-headline{
  position:absolute;left:36px;top:16px;width:210px;margin:0;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  font-family:"Chivo Mono",ui-monospace,monospace;font-size:13px;line-height:19px;color:var(--ochre);
}
.join-card-offer-detail{
  position:absolute;left:36px;top:38px;width:286px;margin:0;
  font-family:"Chivo Mono",ui-monospace,monospace;
  font-size:9px;line-height:12px;letter-spacing:.54px;color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.join-card-stamp{
  position:absolute;left:258px;top:-10px;transform:rotate(-6deg);
  font-family:"Chivo Mono",ui-monospace,monospace;font-weight:600;
  font-size:9px;line-height:12px;letter-spacing:1.08px;color:var(--ochre);
  border:1.5px solid var(--ochre);border-radius:6px;padding:7px 12px;
}

/* The roster photograph offered as the default on the photo step. Same box as
   a chosen file's preview, so swapping one for the other does not move the
   zone. */
.join-drop-roster{max-height:200px;border-radius:var(--r-card);}

/* ---------- P0 and P0b · what we ask ----------
   The rail's replacement on the two screens that come before a role, where
   there is no card of the visitor's to fill in. A list, not a device: what the
   form is going to ask, and how long it takes. */
.join-rail.is-asks{display:none;}
@media (min-width:1000px){
  .join-rail.is-asks{
    display:flex;align-items:center;
    position:sticky;top:0;height:100vh;overflow:hidden;background:var(--surface);
  }
  /* No fades here — nothing runs off the panel, so there is no cut to cover. */
  .join-rail.is-asks::before,.join-rail.is-asks::after{content:none;}
}

.join-asks{padding:0 72px;max-width:604px;}
.join-asks-title{color:var(--muted);margin:0 0 27px;}

.join-asks-list{list-style:none;margin:0 0 25px;padding:0;}
.join-ask{display:flex;align-items:baseline;gap:14px;margin:0 0 25px;}
.join-ask:last-child{margin-bottom:0;}

.join-ask-n{
  flex:none;width:30px;font-weight:600;font-size:12.5px;line-height:15px;
  letter-spacing:-.005em;color:var(--line-strong);
}
.join-ask-label{
  font-family:Archivo,sans-serif;font-weight:600;font-size:17px;line-height:21px;
  letter-spacing:-.022em;color:var(--muted);
}
/* The step you are on, and only that one. */
.join-ask.is-now .join-ask-n{color:var(--primary);}
.join-ask.is-now .join-ask-label{color:var(--ink);}

.join-asks-time{
  margin:0;padding-top:24px;border-top:1px solid var(--line);
  font-size:14px;line-height:20px;color:var(--faint);
}
