/* ============================================================================
   THE ROSTER: THE STOP WHERE SEATS ARE SET ASIDE FOR EVERYBODY ELSE

   ONE PANEL, ONE LINE PER PERSON, READ TOP TO BOTTOM. The stop used to be two
   empty boxes with an "Add another" button under them, which is the shape of a
   form: it asks somebody to imagine the list they are making. This draws the
   list. The person reading is the first line of it with the seat they already
   hold, every colleague they add lands under theirs, and the last line is where
   the next address goes. What is about to happen is on the screen before it
   happens.

   THE SEAT IS THREE SEGMENTS AND NEVER A MENU, and that is the change this
   whole file exists for. A select hides its own contents until it is opened, so
   an admin in their first two minutes had to open one three times per colleague
   to find out what the three seats were. Here all three are printed, the lit one
   is the one that is set, and each carries its meaning through the console's own
   tooltip (rule 16).

   IT NEVER SCROLLS THE SCREEN, which is the one measurable thing asked of it. A
   list you have to push out of the way to reach the button that finishes it is
   a list nobody adds a fifth name to, so past three people the rows step down
   (`[data-many]`, written by step-invite.ts) and five cost about the air three
   did. The height ladder at the foot of this file does the same again for a
   window that is short rather than a list that is long: they fail differently
   and console-ask.css already argues why they are two axes rather than one.

   EVERY COLOUR IS A ROLE TOKEN, so light and dark both resolve out of
   console-theme.css and there is not one prefers-color-scheme block here.

   NO ACCENT RAIL and no second veil. The panel is a hairline, a radius and the
   console's own surface, exactly as every other bordered block in this product.

   LOAD ORDER: after console-forms.css (it takes the box off `.cb-input`) and
   after console-ask.css (it sits inside `.cb-ask-page` and leans on the
   entrance that file staggers).
   ========================================================================= */

/* ---- The card's body ----
   One column, and no top margin of its own: the standfirst above already
   carries the gap before the answers on every other card of this run, and two
   margins meeting in a plain block collapse to the larger, so writing a second
   one here would only be a number that never applies. */
.cb-settle-team {
  display: grid;
  gap: var(--cb-space-lg);
}

/* ---- The mark: somebody joining ----

   THE THIRD GESTURE OF THREE, AND IT HAD TO BE ITS OWN. The second step draws a
   shield's perimeter and places what is guarded inside it, because a factor is
   a boundary closing around something. The profile stop writes a signature,
   left to right with a travelling nib, because that stop is somebody putting
   their name to their own details. This one was a static icon that simply
   appeared, and next to two marks that do something it read as the screen
   nobody had finished.

   So it does what the screen is for: one person is already here, and another
   arrives beside them. The figure in front draws itself; the one behind comes
   in from off to the left once there is somebody to arrive beside, and a ring
   goes out of the pair as they land.

   Nothing is hand-drawn (docs/10). lucide's `users-round` is already two
   people: the front one is the first path and the circle, the one behind is the
   second path. All this decides is the order. Matched by position rather than by
   class, because the file is a dependency and adding one would mean editing
   something the package owns; if lucide ever reorders them the mark still
   arrives, in the wrong order, which is visible immediately.

   ---- ONE CLOCK, FOUR PARTS, AND EVERY WAIT WRITTEN INSIDE A KEYFRAME ----

   The second step's own construction, worn here, and it is not decoration. The
   four below all run for --cbc-mark-run and each holds at its opening value until
   its turn, so this is one animation with four voices rather than four with
   matching delays.

   It was built with delays first and it was visibly worse. An `animation-delay`
   with `backwards` holds an element out of its resting state, and this mark is
   ALSO a child of the card, arriving on the card's own stagger at the same
   moment (console-ask.css `.cb-ask-page > *`): the figures drew while the box
   holding them was still travelling, which is two gestures over one object.
   Waits inside the keyframes mean the first tenth of the clock is a hold, the
   card lands inside it, and the drawing starts on a mark that has arrived.

   READ AS MILLISECONDS, AND THE ARITHMETIC HERE WAS WRONG TWICE OVER. The
   clock is --cbc-mark-run, which is four --cb-motion-slow and therefore 1600,
   not the twelve hundred this comment and the two beside it all claimed. And
   the whole mark now starts one --mark-in after the card is inserted, so it
   arrives with its card rather than over the top of the one still leaving
   (console-ask.css). Counting from the moment the card goes in: the one
   already here draws 310 to 982, the one arriving 918 to 1334, the pair settle
   950 to 1302, and the ring goes out from 982 and is gone by the end at 1750.*/
/* THE BOX IS `.cb-page-mark` IN console-ask.css and only what this mark IS lives
   here. This block was also written out TWICE in this file, thirty lines apart,
   with two different arguments over it: one of them saying the mark sits at the
   start of a left-aligned card, which the code beside it then centred. Both
   copies said 128 and 1.25, the profile stop's file said 128 and 1.5 with no air
   under it at all, and the second step's said 128 and 0.5 with sixteen. On an
   ordinary laptop those three ladders had them drawing at 128, 96 and 64, so a
   run of three screens changed the size, the weight AND the position of its
   largest element every time somebody pressed a button. One box, three drawings.

   THE MARK IS CENTRED, and the argument that used to be here for putting it at
   the start was about a different card: page.ts stamps `[data-mark]` and
   console-settle.css centres every card that has one, because these two stops
   are one object in the middle of a plane the way the lock next door is. */
/* ---- And the one rung this card takes for itself ----

   THE MARK GIVES WAY TO PEOPLE, AND ONLY TO PEOPLE. The shared ladder in
   console-ask.css is written for a card whose height is fixed: a mark, a
   heading, a sentence and a thing to press. This is those plus a panel that
   grows by a row for every colleague, and the one measurable thing asked of
   this stop is that it never makes the screen scroll: a list you have to push
   out of the way to reach the button that finishes it is a list nobody adds a
   fifth name to.

   SO IT IS KEYED ON THE LIST BEING LONG rather than on this being the team
   stop. `[data-many]` is already written by step-invite.ts at the point the
   rows themselves step down, which is three colleagues or more, and it is the
   only moment the room is genuinely needed. Every ordinary run of this stop has
   nobody or one or two people on it and draws the mark at exactly the size the
   two screens either side of it do, which is the whole point of the ladder
   being shared. A card that was permanently a size smaller than its neighbours
   because of a list it usually does not have would be the old bug with a better
   excuse.

   ONE STEP, at each of the rungs where a step is left to take. Below 560 the
   mark is already at the size the lockup is drawn at and there is nowhere
   further down to go. */
.cb-ask-page:has(.cb-roster[data-many]) > .cb-page-mark {
  --mark-size: var(--cb-space-9xl);
  margin-block-end: var(--cb-space-lg);
}
@media (max-height: 1024px) {
  .cb-ask-page:has(.cb-roster[data-many]) > .cb-page-mark {
    --mark-size: var(--cb-space-7xl);
  }
}
@media (max-height: 560px) {
  .cb-ask-page:has(.cb-roster[data-many]) > .cb-page-mark {
    --mark-size: var(--cb-space-6xl);
    margin-block-end: var(--cb-space-md);
  }
}

.cb-settle-mark {
  /* Run by console-ask.css alongside the card's own entrance. An `animation`
     shorthand here lands later in the cascade at the same weight as the
     entrance `.cb-ask-page > *` gives every band of a card, and replaced it:
     the mark appeared at full opacity on frame zero, over the top of the card
     that had not finished leaving. */
  --mark-settle: cbc-join-settle;
  /* How far the one arriving comes from, in the icon's OWN units: a CSS
     transform on an SVG child moves in user space, and this icon is drawn in a
     24-unit box, so three is about a shoulder's width at any size it is set
     at. */
  --join-step: 3px;
}

/* The one already here. 44 is the head and the shoulders' own length rounded
   comfortably up, which is the trick the other two marks use: one number covers
   a path whose exact length nobody here has to know. */
.cb-settle-mark svg circle,
.cb-settle-mark svg path:nth-of-type(1) {
  stroke-dasharray: 44;
  animation: cbc-join-drawn var(--cbc-mark-run) var(--cb-motion-ease) var(--mark-in, 0s) both;
}
/* And the one arriving, once there is somebody to arrive beside. ONE PATH, not
   two: lucide's users-round is a path, a circle and a path, so the figure in
   front is the first path plus the circle and the one behind is the second path
   and nothing else. There was a `:nth-of-type(3)` here matching nothing, with a
   comment above saying the one behind was "the other two". */
.cb-settle-mark svg path:nth-of-type(2) {
  transform-box: fill-box;
  transform-origin: center;
  animation: cbc-join-in var(--cbc-mark-run) var(--cbc-spring) var(--mark-in, 0s) both;
}
/* AND ONE RING OUT OF THE PAIR, which is the whole of the flourish and is the
   console's own way of saying a thing landed: the second step's mark does it,
   and so do the ticks on the last onboarding card. Two surfaces in one product
   should not each invent their own.

   Two pixels because a ring off a mark is a hairline by any other name, which
   is the token guard's own exemption. Behind everything, and gone before
   anybody has finished the heading. */
.cb-settle-mark::after {
  content: "";
  position: absolute;
  inset: var(--cb-space-sm);
  z-index: -1;
  border: 2px solid var(--cbc-accent);
  border-radius: var(--cb-radius-full);
  opacity: 0;
  animation: cbc-join-ring var(--cbc-mark-run) var(--cb-motion-ease) var(--mark-in, 0s) backwards;
}

/* THE FOUR BEATS ARE THE SECOND STEP'S OWN, SHIFTED RIGHT BY THE ARRIVAL, and
   the shift is the part that was learned the hard way. The shield draws over a
   room that has already faded in: its surface arrives first, then its mark
   performs. This card TURNS in mid-run, and the mark used to start performing
   at insert, so for the first four hundred milliseconds the strokes were
   drawing head-and-shoulder fragments in mid-air over a page whose title and
   rows were still staggering in. Filmed frame by frame: at 90ms a floating red
   squiggle above a lone ghost title, the exact opposite of "content settles
   into a container that has already arrived" (rule 14).

   So the clock holds through the card's own entrance. The wait lives INSIDE
   the keyframes, never in animation-delay, which is the same one-clock rule
   every mark here follows: a delay leaves the first painted frame at whatever
   the property's base value is, and for a dash-drawn path that is the whole
   figure visible before it starts drawing itself.

   A quarter of the run is the arrival window: --cbc-mark-run is four slow
   tokens and the card's stagger has finished inside one and a half of them,
   so at 26% the ground below this mark is standing still. After the hold, the
   shield's own shape: draw, then the one arriving, the weight taken, one ring
   out, all resolved by nine tenths.

   The one thing that stays this mark's own is WHAT arrives: a person
   travelling in from the left rather than a glyph being placed, so there is no
   overshoot on it. A shield being closed around something can go a hair past
   its size and come back; somebody walking up beside you cannot. */
@keyframes cbc-join-drawn {
  0%,
  26% {
    stroke-dashoffset: 44;
  }
  62%,
  100% {
    stroke-dashoffset: 0;
  }
}
@keyframes cbc-join-in {
  0%,
  58% {
    opacity: 0;
    transform: translateX(calc(var(--join-step) * -1));
  }
  78% {
    opacity: 1;
  }
  82%,
  100% {
    opacity: 1;
    transform: none;
  }
}
/* The pair take the weight of the second one landing. One settle, three per
   cent, on the frame the first figure is finished and the second is on its way
   in. Three rather than the shield's four and a half: a shield closing around
   something is a bigger event than somebody arriving beside somebody. */
@keyframes cbc-join-settle {
  0%,
  64% {
    transform: scale(1);
  }
  70% {
    transform: scale(1.03);
  }
  84%,
  100% {
    transform: scale(1);
  }
}
@keyframes cbc-join-ring {
  0%,
  62% {
    opacity: 0;
    transform: scale(0.96);
  }
  72% {
    opacity: 0.3;
  }
  100% {
    opacity: 0;
    transform: scale(1.55);
  }
}

/* ---- The panel ----

   NO `overflow: hidden`, however much a rounded box full of rows wants it. It
   would clip the two-pixel focus ring off the first and last rows, which is the
   one thing a keyboard reader here cannot do without (console-ask.css carries
   the same note about the measure). The corners are put on the first and last
   rows instead, so a row that lights up under a caret still lights up inside the
   panel's own shape.

   The two measurements the rows read are set here rather than on each row, so
   the whole list steps together and there is one place to change it. */
.cb-roster {
  --roster-air: var(--cb-space-lg);
  --roster-side: var(--cb-space-2xl);
  --roster-face: var(--cb-space-4xl);
  display: grid;
  border: 1px solid var(--cbc-line);
  border-radius: var(--cb-radius-3xl);
  background: var(--cbc-surface);
}

/* ---- One line ----
   A face, an address, the seat, and the way off. Four columns, the address
   taking whatever is left, so every seat control down the list starts in the
   same place and the column reads as a column. */
.cb-roster-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--cb-space-xl);
  padding: var(--roster-air) var(--roster-side);
  transition: background var(--cb-motion-fast) var(--cb-motion-ease);
}
/* Hairlines between the lines and not around each one. A list is one object
   with divisions in it; a stack of separately bordered boxes is a set of cards
   that happen to be touching. */
.cb-roster-row + .cb-roster-row {
  border-block-start: 1px solid var(--cbc-line);
}
.cb-roster-row:first-child {
  border-start-start-radius: var(--cb-radius-3xl);
  border-start-end-radius: var(--cb-radius-3xl);
}
.cb-roster-row:last-child {
  border-end-start-radius: var(--cb-radius-3xl);
  border-end-end-radius: var(--cb-radius-3xl);
}
/* A row lights when the caret is in it and not when a pointer passes over it.
   Hover is the gesture before pressing and nothing here is pressable as a whole;
   focus-within is the moment somebody is actually working on this line, which is
   the same rule the other form stop's rows follow. */
.cb-roster-row:focus-within {
  background: var(--cbc-hover);
}

/* ---- The face ----
   `.cb-avatar` is the console's own disc (console.css) and draws itself from a
   name or an address, so a colleague who has never signed in still has initials
   rather than an empty circle. What is set here is only the size, which steps
   with the list. */
.cb-roster .cb-avatar {
  inline-size: var(--roster-face);
  block-size: var(--roster-face);
}
/* The last line is not a person yet, and the outline is what says so. Dashed
   rather than a plain circle, because a solid empty disc reads as somebody whose
   picture failed to load. */
.cb-roster-new {
  display: grid;
  place-items: center;
  flex: none;
  inline-size: var(--roster-face);
  block-size: var(--roster-face);
  border: 1px dashed var(--cbc-line-strong);
  border-radius: var(--cb-radius-full);
  color: var(--cbc-ink-faint);
  transition: color var(--cb-motion-fast) var(--cb-motion-ease);
}
.cb-roster-add:focus-within .cb-roster-new {
  color: var(--cbc-accent);
}
.cb-roster-new .cb-icon {
  inline-size: var(--cb-space-2xl);
  block-size: var(--cb-space-2xl);
}

/* ---- The address ----
   Written straight onto the row. There is no box round it because the row is the
   box, which is the rule the other form stop's controls already follow. */
.cb-roster-said {
  display: flex;
  align-items: baseline;
  gap: var(--cb-space-md);
  min-inline-size: 0;
}
.cb-roster-mail {
  overflow: hidden;
  font-size: var(--cb-type-base-size);
  line-height: var(--cb-type-base-line-height);
  color: var(--cbc-ink);
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* "you", and it is a word rather than a badge. A tag with a ground and a border
   beside somebody's own address would be the loudest thing in a column whose
   whole job is to be read quietly; faint lowercase says the same and says it
   once. */
.cb-roster-you {
  flex: none;
  font-size: var(--cb-type-xs-size);
  line-height: var(--cb-type-xs-line-height);
  color: var(--cbc-ink-faint);
}

/* ---- The seat ----
   A track with three seats in it and one of them raised. The chosen one is
   lifted off the track rather than filled with the accent: this control is read
   down a column three or five times over, and three scarlet pills stacked up
   would be the first thing anybody saw on a screen about something else. */
.cb-roster-seats {
  display: inline-flex;
  flex: none;
  gap: var(--cb-space-xxs);
  padding: var(--cb-space-xxs);
  border-radius: var(--cb-radius-full);
  background: var(--cbc-sunken);
}
.cb-roster-seat {
  padding: var(--cb-space-xs) var(--cb-space-lg);
  border: 0;
  border-radius: var(--cb-radius-full);
  background: none;
  color: var(--cbc-ink-faint);
  cursor: pointer;
  font: inherit;
  font-size: var(--cb-type-xs-size);
  line-height: var(--cb-type-xs-line-height);
  font-weight: var(--cb-font-weight-medium);
  white-space: nowrap;
  transition:
    background var(--cb-motion-fast) var(--cbc-spring),
    color var(--cb-motion-fast) var(--cbc-spring);
}
.cb-roster-seat:hover {
  color: var(--cbc-ink);
}
.cb-roster-seat[aria-checked="true"] {
  background: var(--cbc-surface);
  color: var(--cbc-ink);
  box-shadow: var(--cb-shadow-card);
}
/* Turned off, never taken away (rule 15), and it holds its ground and its
   words: a seat that has been set aside is still a fact worth reading, and the
   tooltip on it is the only place the reason lives. */
.cb-roster-seat[aria-disabled="true"] {
  cursor: default;
}
.cb-roster-seat[aria-disabled="true"]:hover {
  color: var(--cbc-ink-faint);
}
.cb-roster-seat[aria-disabled="true"][aria-checked="true"]:hover {
  color: var(--cbc-ink);
}
.cb-roster-seat:focus-visible {
  outline: var(--cbc-focus);
  outline-offset: var(--cbc-focus-gap);
}

/* ---- The end of a line ----
   The way off, the way on, and the tick that replaces the way off once the
   server has taken an address. One slot, because a line that has been taken is
   not a line to take off any more, and a fifth column that is empty on every
   other row is a column that is not a column. */
.cb-roster-end {
  position: relative;
  display: grid;
  place-items: center;
  flex: none;
  inline-size: var(--cb-space-4xl);
  block-size: var(--cb-space-4xl);
}
.cb-roster-end > * {
  grid-area: 1 / 1;
}
.cb-roster-off,
.cb-roster-put {
  display: grid;
  place-items: center;
  inline-size: 100%;
  block-size: 100%;
  padding: 0;
  border: none;
  border-radius: var(--cb-radius-md);
  background: none;
  color: var(--cbc-ink-faint);
  cursor: pointer;
  opacity: 0;
  transition:
    opacity var(--cb-motion-fast) var(--cbc-spring),
    background var(--cb-motion-fast) var(--cbc-spring),
    color var(--cb-motion-fast) var(--cbc-spring);
}
/* Quiet until a pointer comes near the line it belongs to, which is the rule the
   dashboard's drag handles follow: one affordance at a time, and only for the
   row somebody is actually on. It stays hoverable while it is invisible, which
   is what lets a control that is turned off still explain itself. */
.cb-roster-row:hover .cb-roster-off,
.cb-roster-row:focus-within .cb-roster-off {
  opacity: 1;
}
/* The plus is the exception, and it earns it: the moment there is an address in
   the box, the way to put it on the list is the next thing anybody wants and
   should not have to be found by hovering. */
.cb-roster-put:not([aria-disabled="true"]) {
  opacity: 1;
  color: var(--cbc-accent);
}
.cb-roster-add:hover .cb-roster-put,
.cb-roster-add:focus-within .cb-roster-put {
  opacity: 1;
}
.cb-roster-off:hover {
  background: var(--cbc-hover);
  color: var(--cbc-ink);
}
/* The plus keeps its accent under the pointer rather than going to ink with
   everything else: it is the one control in this column that adds something,
   and a live control that greys out on approach reads as one that has just
   stopped applying. */
.cb-roster-put:not([aria-disabled="true"]):hover {
  background: var(--cbc-accent-quiet);
}
.cb-roster-off:focus-visible,
.cb-roster-put:focus-visible {
  opacity: 1;
  outline: var(--cbc-focus);
  outline-offset: var(--cbc-focus-gap);
}
.cb-roster-off[aria-disabled="true"],
.cb-roster-put[aria-disabled="true"] {
  cursor: default;
}
.cb-roster-off[aria-disabled="true"]:hover,
.cb-roster-put[aria-disabled="true"]:hover {
  background: none;
  color: var(--cbc-ink-faint);
}

/* A line the server has taken. It reads as done rather than as unavailable: the
   address stays legible, the face goes to the accent the way a chosen answer
   does, and the tick takes the corner. */
.cb-roster-tick {
  display: none;
  color: var(--cbc-good-text);
}
.cb-roster-row[data-sent] .cb-roster-tick {
  display: grid;
}
.cb-roster-row[data-sent] .cb-roster-off {
  display: none;
}
.cb-roster-row[data-sent] .cb-avatar {
  background: var(--cbc-accent-wash);
  color: var(--cbc-accent);
}
.cb-roster-row[data-sent] .cb-roster-mail {
  color: var(--cbc-ink-muted);
}

/* ---- Where the next address is typed ----
   The box comes off `.cb-input` entirely: the row already has the hairline and
   the radius, and a field bringing its own would be two frames around one thing,
   which is what made the first cut of these stops read as a form pasted onto a
   page. The row's own focus-within is the ring. */
.cb-roster .cb-roster-entry {
  inline-size: 100%;
  /* Not zero: an input clips its own painting, so a caret standing at the
     first pixel of an empty field is drawn half-shaved. Two pixels is caret
     room (hairline exemption, rule 13), and the negative margin hands them
     straight back so the typed address still sits flush with the addresses
     in the rows above. */
  padding: 0 2px;
  margin-inline: -2px;
  border: none;
  background: none;
  color: var(--cbc-ink);
  font-size: var(--cb-type-base-size);
  line-height: var(--cb-type-base-line-height);
}
.cb-roster .cb-roster-entry:hover {
  border-color: transparent;
}
.cb-roster .cb-roster-entry:focus,
.cb-roster .cb-roster-entry:focus-visible {
  outline: none;
  box-shadow: none;
}

/* ---- What the server said about one address ----
   Under the line it is about, indented to the words rather than to the panel's
   edge, so a refusal can never be read against the wrong person. It takes no
   room at all when there is nothing to say: a permanently reserved error line is
   a screen that looks like it is about to go wrong. */
.cb-roster-note {
  grid-column: 2 / -1;
  margin: 0;
  font-size: var(--cb-type-sm-size);
  line-height: var(--cb-type-sm-line-height);
  color: var(--cbc-poor-text);
}
.cb-roster-note:empty {
  display: none;
}

/* ---- Once the list is longer than three ----
   Written by step-invite.ts, because CSS cannot count its own children into a
   decision and a chain of `:has(:nth-child(n))` would say the same thing four
   times. The air gives way first and the faces come down with it, so five people
   cost about what three did and the button at the bottom stays where it was. */
.cb-roster[data-many] {
  --roster-air: var(--cb-space-md);
  --roster-side: var(--cb-space-xl);
  --roster-face: var(--cb-space-3xl);
}
.cb-roster[data-many] .cb-roster-row {
  gap: var(--cb-space-lg);
}
.cb-roster[data-many] .cb-roster-mail,
.cb-roster[data-many] .cb-roster-entry {
  font-size: var(--cb-type-sm-size);
  line-height: var(--cb-type-sm-line-height);
}

/* ---- Narrow windows ----
   480px mirrors tokens.width.sm, which is the width console-ask-form.css already
   uses for the same failure: an address and a three-word control side by side
   leave about six characters of an email showing, and a field nobody can check
   what they typed into is worse than a row that takes two lines. */
@media (max-width: 480px) {
  .cb-roster-row {
    grid-template-columns: auto minmax(0, 1fr) auto;
    row-gap: var(--cb-space-md);
  }
  /* Every seat placed by hand once the seat control drops to its own line.
     Left to auto-placement the way off would follow it down and the column of
     controls would come apart, which is the thing rule 15 is about drawn in
     layout rather than in a disabled attribute. */
  .cb-roster-face {
    grid-area: 1 / 1;
  }
  .cb-roster-said,
  .cb-roster .cb-roster-entry {
    grid-area: 1 / 2;
  }
  .cb-roster-end {
    grid-area: 1 / 3;
  }
  .cb-roster-seats {
    grid-row: 2;
    grid-column: 2 / -1;
  }
  .cb-roster-note {
    grid-row: 3;
    grid-column: 1 / -1;
  }
}

/* ---- Short windows ----

   THE OTHER AXIS, AND IT FAILS DIFFERENTLY. Narrow, the type runs out of line
   length; short, there is nothing wrong with the type and everything wrong with
   the air around it. console-ask.css and console-gate.css both carry that
   argument and both step in this order, so the mark comes down the scale, the
   list closes up, and nothing that is pressed ever gets smaller than a target.

   A laptop advertised as 1440 by 900 hands a browser about eight hundred pixels
   once its own chrome is out of the way, so the first rung is not the degraded
   layout, it is the ordinary one. */
/* 1024px mirrors tokens.breakpoint.lg, on the height axis */
@media (max-height: 1024px) {
  .cb-roster {
    --roster-air: var(--cb-space-md);
  }
}
/* 768px mirrors tokens.breakpoint.md, on the height axis. This is the rung that
   has to hold a list of five with a heading, a standfirst, a button and a line
   of small print above and below it. */
@media (max-height: 768px) {
  .cb-roster {
    --roster-air: var(--cb-space-sm);
    --roster-side: var(--cb-space-xl);
    --roster-face: var(--cb-space-3xl);
  }
  .cb-roster-row {
    gap: var(--cb-space-lg);
  }
  .cb-roster-mail,
  .cb-roster .cb-roster-entry {
    font-size: var(--cb-type-sm-size);
    line-height: var(--cb-type-sm-line-height);
  }
}
/* 640px mirrors tokens.width.lg, on the height axis, the way the width query
   above mirrors width.sm.

   THE MARK TAKES ITS LAST STEP HERE rather than going away, which is what
   console-gate.css does at the bottom of its own ladder: forty pixels still
   reads as a mark, and a screen that drops one band entirely at a certain height
   is a screen that looks like two different designs to two people. Everything
   else on the card is the question, the list or the way on, so the air is what
   gives way and the list stays whole. The lockup at the top of the plane is
   untouched, as it is at every other rung: that one is the identity carried
   across from the sign-in door, and console-ask.css says why it holds its size.*/
@media (max-height: 640px) {
  .cb-roster {
    --roster-air: var(--cb-space-xs);
    --roster-face: var(--cb-space-3xl);
  }
  .cb-settle-team {
    gap: var(--cb-space-md);
  }
}
/* 480px mirrors tokens.breakpoint.sm, on the height axis, and it is the last
   rung there is. NOTHING PRESSABLE SHRINKS BELOW THIS: a 480-pixel window is a
   phone held sideways as often as it is a laptop with too many toolbars, and a
   control shaved under the touch target is a worse outcome than a panel that
   scrolls inside itself. So the list keeps its rows and gets a ceiling instead,
   with its own scrollbar rather than the screen's. */
@media (max-height: 480px) {
  .cb-roster {
    max-block-size: calc(var(--cb-space-11xl) + var(--cb-space-5xl));
    overflow-y: auto;
  }
}
