/* ---- The security gate ----

   THE SETUP QUESTIONS' SCREEN, WITH A CODE ON IT INSTEAD OF A QUESTION. This
   file is deliberately short, and that is the point of it: the two planes, the
   picture, the drift on it, the wash over it, the lockup at the top of the
   panel, the three bands under it, the measure down the middle, the foot with
   its three seats and the hairline along the bottom edge are all
   console-ask.css, worn here because the root carries `.cb-ask`. Every
   prospect's first minute is sign in, then this, then four questions, and until
   now the middle one was a 480-pixel column on a flat ground: the same product,
   one step apart, looking like two.

   SO WHAT IS BELOW IS ONLY WHAT A CODE SCREEN HAS AND A QUESTION DOES NOT: the
   mark, the square, the six slots, the ten codes, and the ground rules the
   `<dialog>` element was giving `.cb-ask` for free.

   IT IS NOT A DIALOG, AND src/mfa/surface.ts CARRIES THE ARGUMENT. In short:
   `dialog.cb-ask` is swept by name every time the console rebuilds its shell,
   and an hourly token refresh rebuilds the shell, so a gate raised mid-session
   would be tidied away in the middle of somebody typing a code. It is also what
   this screen has always been.

   NO CANDY MOTIF, which docs/09 allows one of. The brand's mark is already at
   the top of the plane and the brand's scarlet is already on the shield, the
   filled slots and the button. A sweet on top of that would be the fourth thing
   saying whose product this is on a screen whose one job is to ask for six
   digits.

   NO ACCENT RAIL, and nothing invents a second veil: what dims the photograph
   is `.cb-ask-shade`, which is the console's own veil at a fraction of itself.

   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.

   THERE IS NO REDUCED-MOTION BLOCK EITHER, and what that costs is written into
   two decisions further down rather than into a rule. The global blocks cut
   duration to a millisecond; the media-query one cuts delay too and the
   console's own `[data-motion="reduced"]` switch does not. So nothing on this
   surface buys a wait with an animation-delay: every hold is a flat opening
   inside its own keyframe, which collapses to one frame at the resting value
   under either switch. And the one thing a stylesheet cannot cut at all, the
   beat held by a timer after a code is accepted, is simply not run for somebody
   who asked for less (surface.ts). The two stagger tokens are the exception,
   deliberately: --cbc-step and --cbc-step-fine are how every list in this
   console arrives and a second answer here would only be this screen
   disagreeing with the rest of it.

   LOAD ORDER: after console-forms.css and after console-ask.css. It overrides
   `.cb-input` on the code entry and leans on `.cb-ask-*` for everything else. */

/* ---- The plane ----
   The same viewport rules `dialog.cb-ask` gives itself, said again because a
   div gets none of them for free, plus the two a dialog would have handled: it
   is fixed over whatever is already drawn, and it owns the screen while it is
   up. --cbc-z-gate is the layer a full-bleed surface takes, which is what this
   has always used.

   --ask-span is the width the two planes divide up. 100vw is only the fallback;
   stage.ts measures the real one before anything paints, because the two stop
   being the same number the moment a scrollbar is showing. */
.cb-lock {
  --ask-span: 100vw;
  position: fixed;
  inset: 0;
  z-index: var(--cbc-z-gate);
  inline-size: 100vw;
  max-inline-size: 100%;
  block-size: 100svh;
  max-block-size: 100svh;
  overflow: hidden;
  background: var(--cbc-surface);
  color: var(--cbc-ink);
  /* cbc-fade and not cbc-rise. Twenty pixels of travel is for a box arriving
     over a page; this IS the page, and a page does not slide in from below.
     It also covers the one cut in the sequence: the wall behind is at the
     sign-in split and this opens at the questions' own, so the two planes
     trade width under an opacity that has not finished arriving yet. */
  animation: cbc-fade var(--cb-motion-base) var(--cb-motion-ease) backwards;
}
/* Leaving: it fades off whatever is arriving underneath rather than cutting to
   it, which is the same argument onboarding/dialog.ts makes for the questions.
   cbc-ask-adieu is that file's keyframe and this is the second thing it is for:
   a surface being replaced in place by what is already behind it. */
.cb-lock[data-going] {
  pointer-events: none;
  animation: cbc-ask-adieu var(--cb-motion-slow) var(--cb-motion-ease) forwards;
}

/* ---- The card ----
   Centred, which is the one place this parts company with a question. A
   question is a list of answers read down its left edge; this is one object, a
   sentence about it and one thing to press, and a column of three centred
   things is what a moment looks like. The measure is `.cb-ask-slot`'s, so the
   heading wraps exactly where a question's does. */
/* text-align only, and NOT `justify-items`. Chrome honours justify-self on a
   block-level box in normal flow, so a centring keyword here quietly turned
   every band on the card into a shrink-to-fit box: the setting-up step's two
   columns collapsed to the width of their own contents and six code slots came
   out nineteen pixels wide. What centres the words is the text alignment, and
   what centres a block is its own auto margins. */
.cb-lock-page {
  text-align: center;
}
.cb-lock-page .cb-ask-lede {
  max-inline-size: var(--cb-width-lg);
  margin-inline: auto;
}

/* ---- The mark ----

   IT WAS A SIXTEEN-PIXEL GLYPH IN A DISC, which is the mark a toast wears. This
   screen is the one place the console asks somebody to go and fetch their
   phone, and the reason it asks is that a laptop left open is a way into every
   prospect's name, address and phone number.

   ONE OBJECT, COMPOSED, NEVER DRAWN BY HAND (docs/10): a lucide shield at 128
   with the thing being guarded standing inside it. No plate behind it, no ring
   around it and no gradient under it. The scale is what carries it, which is
   the whole of what "grand" means here.

   THE STROKES ARE THINNED IN PROPORTION. lucide draws at 2 units in a 24 box;
   at 128 that is a ten-pixel outline, which reads as a sticker. 0.5 and 1.4 put
   the shield and the glyph inside it at roughly two and a half pixels each, so
   they read as one drawing at one weight rather than two icons at two.

   THE BOX IS NOT HERE ANY MORE, and that is the whole of what moved. The size,
   the height ladder, the air under it, the colour and the shield's own half a
   unit are `.cb-page-mark` in console-ask.css now, because they were also being
   written out, differently, by the two settling-in stops next door: three marks
   on three screens of one run at three sizes and three weights. What is left
   here is what this mark IS rather than how big it is. Nothing about how it
   renders changed; that file's ladder is this one's, moved. */
.cb-lock-mark {
  /* Run by console-ask.css alongside the card's own entrance, because a mark
     that carried its own `animation` shorthand replaced that entrance and
     appeared at full opacity over the card that was still leaving. */
  --mark-settle: cbc-lock-settle;
}
/* All three stacked on the same middle. The shield takes the whole box and the
   two that go inside it take the same smaller one as each other, so the check
   lands exactly where the glyph was standing.

   The class is written twice on the shield on purpose. `.cb-lock-mark .cb-icon`
   and `.cb-lock-mark .cb-lock-shield` carry the same weight, so the height steps
   at the bottom of this file, which have to reach the glyph, were quietly
   taking the shield down with them: it drew at the glyph's size, behind the
   glyph, at a stroke thin enough to look like nothing was there at all. */
.cb-lock-mark .cb-icon {
  position: absolute;
}
.cb-lock-mark .cb-icon.cb-lock-shield {
  inline-size: 100%;
  block-size: 100%;
}
.cb-lock-mark .cb-lock-glyph,
.cb-lock-mark .cb-lock-ok {
  inline-size: var(--cb-space-6xl);
  block-size: var(--cb-space-6xl);
}
/* The shield is drawn at a HAIR of the console's stroke and the two marks
   inside it at close to the full one. A 128-pixel outline at the weight a
   16-pixel glyph wants is a heavy black shape; at half a unit it is a line
   somebody drew. The class is written twice on the shield on purpose:
   `.cb-lock-mark .cb-icon` and `.cb-lock-mark .cb-lock-shield` carry the same
   weight, so the height steps at the bottom of this file, which have to reach
   the glyph, were quietly taking the shield down with them. */
.cb-lock-mark .cb-lock-shield svg {
  stroke-width: 0.5;
}
.cb-lock-mark .cb-lock-glyph svg,
.cb-lock-mark .cb-lock-ok svg {
  stroke-width: 1.4;
}

/* THE OUTLINE DRAWS ITSELF, one stroke, and then the thing inside it arrives.
   A mark that is drawn reads as something being done; a mark that fades in
   reads as an image loading, and this is the same idiom the last onboarding
   card already uses for its ticks (console-ask.css `.cb-ask-tick`).

   The dash has to hold what it ends at (`forwards`), because where it ends is
   not where the element rests: at rest the path is hidden. That is the one case
   console-theme.css allows a held animation for.

   60 is the shield's own path length rounded up, and a dasharray comfortably
   longer than the path is what lets one number cover an icon whose exact length
   nobody here has to know. */
.cb-lock-mark .cb-lock-shield svg {
  stroke-dasharray: 60;
  stroke-dashoffset: 60;
  animation: cbc-lock-drawn var(--cbc-mark-run) var(--cb-motion-ease) var(--mark-in, 0s) both;
}
/* Inside the shield, and only once the outline has closed AROUND it. It used to
   arrive at sixty-two per cent of a shorter clock, which put the phone fully
   drawn inside a shield that still had a gap in its right-hand edge: the two
   halves of one object, out of order. It is not arriving from anywhere, so it
   scales rather than travels, and it goes a hair past its size and comes back,
   which is the difference between a thing being placed and a thing resizing. */
.cb-lock-glyph {
  animation: cbc-lock-inside var(--cbc-mark-run) var(--cbc-spring) var(--mark-in, 0s) backwards;
  transition: opacity var(--cb-motion-base) var(--cb-motion-ease);
}
/* THE WHOLE MARK TAKES THE WEIGHT OF THE SHIELD CLOSING. One settle, four per
   cent, on the frame the outline meets itself. Nothing else on this surface
   moves, so it reads as the object locking rather than as an element animating,
   and it is the reason the ring below it has anything to come out of.

   Named at the top of this file as --mark-settle and RUN by console-ask.css,
   second in a list whose last entry is the card's own entrance. It cannot be
   run from here: an `animation` shorthand on this element lands later in the
   cascade at the same weight as the entrance every other band of the card gets,
   and quietly replaces it. */
/* AND ONE RING OUT OF IT, which is the whole of the flourish.

   The same vocabulary as the last onboarding card's ticks (console-ask.css
   `cbc-tick-ping`), at this screen's scale: a mark is made, and something goes
   out from it. Two surfaces in one product should not each invent their own way
   of saying "that landed", and this is the louder of the two because it is a
   128-pixel object on a screen with nothing else on it.

   Round, over a shield, on purpose. The alternative is a second shield scaled
   up behind the first, which at this size reads as a drop shadow that has come
   loose; a circle reads as a pulse coming off the object rather than as a copy
   of it. It is behind everything (z-index below the icons, which are
   positioned) and it is gone before anybody has finished the heading.

   Two pixels because a ring off a mark is a hairline by any other name, which
   is the token guard's own exemption. */
.cb-lock-mark::after {
  content: "";
  position: absolute;
  inset: var(--cb-space-sm);
  border: 2px solid var(--cbc-accent);
  border-radius: var(--cb-radius-full);
  opacity: 0;
  animation: cbc-lock-ring var(--cbc-mark-run) var(--cb-motion-ease) var(--mark-in, 0s) backwards;
}
/* The check waits, invisible, from the first frame. Swapping one icon for
   another in JavaScript at the moment a code is accepted would be a node
   arriving on the one frame the screen is trying to feel finished on. */
.cb-lock-ok {
  opacity: 0;
  stroke-dasharray: 30;
  /* NEGATIVE, so the mark is drawn the way a hand draws it: up the short arm
     from the bottom left, then out along the long one. lucide's check path
     starts at the TOP RIGHT, so a positive offset reveals it from the top of
     the long arm downwards, which is a shape being wiped on rather than a mark
     being made. console-ask.css's `.cb-ask-tick` carries the same two lines and
     the same reason; this is the same icon and it should not be drawn two
     different ways in one product. */
  stroke-dashoffset: -30;
}
.cb-lock-mark[data-done] .cb-lock-glyph {
  opacity: 0;
}
.cb-lock-mark[data-done] .cb-lock-ok {
  opacity: 1;
  animation: cbc-lock-draw var(--cb-motion-base) var(--cb-motion-ease) forwards;
}
/* The dash is on the wrapper for the check and on the svg for the shield,
   because the wrapper is what carries the state and the svg is what carries the
   stroke. Both end up on the path; this puts the value where the rule that
   changes it can reach it. */
.cb-lock-ok svg {
  stroke-dasharray: inherit;
  stroke-dashoffset: inherit;
}
@keyframes cbc-lock-draw {
  to {
    stroke-dashoffset: 0;
  }
}

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

   The four below all run for --cbc-mark-run and each holds at its opening value
   until its turn: the shield draws itself, the mark settles as the outline
   meets itself, the glyph is placed inside it, and a ring goes out.

   READ AS MILLISECONDS, AND THE ARITHMETIC HERE WAS WRONG. --cbc-mark-run is
   four --cb-motion-slow and therefore 1600, not the twelve hundred this comment
   claimed for as long as it has existed. The mark also starts one --mark-in
   after its card is inserted now, so it arrives WITH the card rather than at
   full opacity over the top of the one still leaving (console-ask.css). Counted
   from the moment the card goes in: the shield draws 278 to 982, the mark
   settles 950 to 1302, the glyph is placed 918 to 1334, and the ring goes out
   from 982 and is gone by the end at 1750.

   THE WAITS BETWEEN THE FOUR ARE NOT DELAYS, and the note above
   `.cb-lock-shield` says why at length: they are stops written inside each
   keyframe, so the whole sequence collapses to one frame at its resting value
   when a reader has asked for less motion, which is what a cut means. The one
   delay any of them carries is --mark-in, which is the card's own arrival and
   is zeroed by both reduced-motion rules along with everything else.

   ONE SHARED CLOCK rather than four durations, for the reason the ticks on the
   last onboarding card share a beat: four numbers that have to stay in a
   particular order are four chances for somebody to change one of them. */

@keyframes cbc-lock-drawn {
  0%,
  8% {
    stroke-dashoffset: 60;
  }
  52%,
  100% {
    stroke-dashoffset: 0;
  }
}
@keyframes cbc-lock-settle {
  0%,
  50% {
    transform: scale(1);
  }
  58% {
    transform: scale(1.045);
  }
  72%,
  100% {
    transform: scale(1);
  }
}
@keyframes cbc-lock-inside {
  0%,
  48% {
    opacity: 0;
    transform: scale(0.6);
  }
  62% {
    opacity: 1;
    transform: scale(1.08);
  }
  74%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
}
@keyframes cbc-lock-ring {
  0%,
  52% {
    opacity: 0;
    transform: scale(0.96);
  }
  62% {
    opacity: 0.3;
  }
  100% {
    opacity: 0;
    transform: scale(1.55);
  }
}

/* ---- What to press ----
   Under the work and never in the foot: the foot is the way out, and the way on
   belongs with the thing it is finishing. Larger than the console's ordinary
   button, because on a screen with one object and one action the action is not
   a row control. */
.cb-lock-acts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cb-space-lg);
  justify-content: center;
  margin-block-start: var(--cb-space-3xl);
}
.cb-lock-acts .cb-btn {
  padding: var(--cb-space-lg) var(--cb-space-5xl);
  font-size: var(--cb-type-base-size);
}

/* ---- Six slots ----

   ONE INPUT UNDER SIX BOXES, and src/mfa/digits.ts says why at length: six real
   fields is what breaks paste, the operating system's own one-time-code offer,
   the backspace key and every screen reader. The field is here, it holds the
   whole code, and the boxes are a picture of what is in it.

   The picture goes away the moment the code is not six digits, because a
   recovery code goes in this same box and must never need a different one. */
.cb-lock-code {
  /* HOW TALL A BOX IS, WRITTEN ONCE. The six slots and the wide field a
     recovery code gets are the same control in two moods, so they have to be
     the same height: they were not, and typing the first letter of a recovery
     code walked the whole card sixteen pixels up the screen. One property, read
     by both, stepped once per window size at the bottom of this file. */
  --lock-slot: var(--cb-space-8xl);
  position: relative;
  display: grid;
  inline-size: 100%;
  max-inline-size: var(--cb-width-sm);
  margin-inline: auto;
  cursor: text;
}
.cb-lock-slots {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--cb-space-md);
}
.cb-lock-slot {
  position: relative;
  display: grid;
  place-items: center;
  block-size: var(--lock-slot);
  border: 1px solid var(--cbc-line);
  border-radius: var(--cb-radius-xl);
  background: var(--cbc-sunken);
  color: var(--cbc-ink);
  font-family: var(--cb-font-mono);
  font-size: var(--cb-type-2xl-size);
  font-variant-numeric: tabular-nums;
  transition:
    border-color var(--cb-motion-fast) var(--cb-motion-ease),
    background var(--cb-motion-fast) var(--cb-motion-ease);
}
/* A DIGIT LANDS IN ITS OWN BOX. This is the moment the whole screen is judged
   on: a code read off a phone under mild time pressure arrives with no feedback
   at all in a plain field, and here each figure drops into a slot and the slot
   answers. It is one --cb-motion-base on the spring, per digit, with nothing
   queued behind it, so six digits typed in a second and a half are six separate
   answers rather than one animation somebody has to sit through. */
.cb-lock-slot[data-filled] {
  border-color: var(--cbc-accent);
  background: var(--cbc-accent-quiet);
  animation: cbc-lock-land var(--cb-motion-base) var(--cbc-spring);
}
@keyframes cbc-lock-land {
  from {
    transform: scale(0.84);
  }
}
/* Where the next one goes. The whole row lifts a little when the field has
   focus and one box is lit, which is what says both "this is where you are
   typing" and "this is which one is next" without a word. */
.cb-lock-code:focus-within .cb-lock-slot {
  border-color: var(--cbc-line-strong);
}
.cb-lock-code[data-at="0"] .cb-lock-slot:nth-child(1),
.cb-lock-code[data-at="1"] .cb-lock-slot:nth-child(2),
.cb-lock-code[data-at="2"] .cb-lock-slot:nth-child(3),
.cb-lock-code[data-at="3"] .cb-lock-slot:nth-child(4),
.cb-lock-code[data-at="4"] .cb-lock-slot:nth-child(5),
.cb-lock-code[data-at="5"] .cb-lock-slot:nth-child(6) {
  border-color: var(--cbc-accent);
  background: var(--cbc-hover);
}
/* The caret, drawn rather than the browser's, because the real field is
   invisible and its own caret would sit in the middle of the row instead of in
   the box that is next. Two steps and not a fade: a cursor is on or it is off,
   and one that breathes reads as decoration (console-theme.css's cbc-blink). */
.cb-lock-slot::after {
  content: "";
  position: absolute;
  inline-size: 2px;
  block-size: var(--cb-space-4xl);
  border-radius: var(--cb-radius-full);
  background: var(--cbc-accent);
  opacity: 0;
}
.cb-lock-code[data-at="0"] .cb-lock-slot:nth-child(1)::after,
.cb-lock-code[data-at="1"] .cb-lock-slot:nth-child(2)::after,
.cb-lock-code[data-at="2"] .cb-lock-slot:nth-child(3)::after,
.cb-lock-code[data-at="3"] .cb-lock-slot:nth-child(4)::after,
.cb-lock-code[data-at="4"] .cb-lock-slot:nth-child(5)::after,
.cb-lock-code[data-at="5"] .cb-lock-slot:nth-child(6)::after {
  opacity: 1;
  animation: cbc-blink var(--cbc-loop) steps(2, jump-none) infinite alternate;
}

/* The real field, over the boxes and out of sight. Everything `.cb-input` gives
   it has to be taken back off: it is not a box here, it is the box's contents.
   Scoped by its parent so it wins whatever order the two sheets load in. */
.cb-lock-code .cb-lock-entry {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: transparent;
  caret-color: transparent;
  text-align: center;
  outline: none;
}
/* A selection band over type nobody can see is a grey rectangle with no
   explanation. The slots are the selection somebody can see. */
.cb-lock-code .cb-lock-entry::selection {
  background: transparent;
}

/* ---- And when it is not six digits ----
   A recovery code is letters, figures and a hyphen, and it is nine characters
   long. The slots go, the field itself becomes the box, and nothing the person
   typed is lost or moved: it is one element changing its mind rather than two
   controls swapping places. */
.cb-lock-code[data-long] .cb-lock-slots {
  display: none;
}
.cb-lock-code[data-long] .cb-lock-entry {
  position: static;
  block-size: var(--lock-slot);
  padding-inline: var(--cb-space-xl);
  border: 1px solid var(--cbc-accent);
  border-radius: var(--cb-radius-xl);
  background: var(--cbc-sunken);
  color: var(--cbc-ink);
  caret-color: var(--cbc-accent);
  font-family: var(--cb-font-mono);
  font-size: var(--cb-type-lg-size);
  letter-spacing: var(--cb-tracking-sm);
}

/* ---- No ----
   Twice, over a quarter second, about the width of one slot and then half of
   it. Enough to read as a refusal, short enough that nobody watching their own
   typing loses their place. It is never the only thing said: the sentence under
   the row carries the server's own words, because colour and movement are not
   labels. The slots tint on the way through and end where they rest, so nothing
   is left red on an empty box. */
.cb-lock-code[data-refused] .cb-lock-slots {
  animation: cbc-lock-no var(--cb-motion-base) var(--cb-motion-ease);
}
.cb-lock-code[data-refused] .cb-lock-slot {
  animation: cbc-lock-no-tint var(--cb-motion-slow) var(--cb-motion-ease);
}
@keyframes cbc-lock-no {
  20% {
    transform: translate3d(calc(var(--cb-space-lg) * -1), 0, 0);
  }
  50% {
    transform: translate3d(var(--cb-space-lg), 0, 0);
  }
  80% {
    transform: translate3d(calc(var(--cb-space-sm) * -1), 0, 0);
  }
}
@keyframes cbc-lock-no-tint {
  0%,
  60% {
    border-color: var(--cbc-poor);
  }
}

/* ---- Yes ----
   The six light one after another rather than all at once, which is the code
   being taken rather than a colour changing. --cbc-step is the console's own
   stagger, capped, off the --i digits.ts writes on each slot. */
.cb-lock-code[data-won] .cb-lock-slot {
  border-color: var(--cbc-accent);
  background: var(--cbc-accent-wash);
  animation: cbc-lock-land var(--cb-motion-base) var(--cbc-spring) backwards;
  animation-delay: var(--cbc-step);
}

/* ---- The refusal in words ----
   Centred with the row it belongs under, and it keeps its line whether or not
   there is anything in it: a sentence appearing under six boxes must not push
   the button it sits above down the screen. */
/* HELD OPEN WHILE IT IS EMPTY, which is the whole reason this line has a rule
   at all. Taking no room until a refusal happens and then taking thirty-six
   pixels walks the six slots and the button up the screen at the exact moment
   somebody is told to try again, and the button they are reaching for is no
   longer under their hand. `hidden` cannot do this: it is
   `display: none !important` console-wide (console-theme.css), so card.ts
   carries the state on an attribute instead and this is the half that draws
   it. */
.cb-lock .cb-lock-problem {
  min-block-size: var(--cb-type-sm-line-height);
  margin: 0;
  font-size: var(--cb-type-sm-size);
  line-height: var(--cb-type-sm-line-height);
  text-align: center;
  visibility: hidden;
}
.cb-lock .cb-lock-problem[data-said] {
  visibility: visible;
  animation: cbc-emerge var(--cb-motion-base) var(--cbc-spring);
}

/* ---- Setting it up: the square and the field, side by side ----
   Stacked, the box you type into sits below a 240-pixel image and below a fold,
   which on the window most people actually have is off the bottom of the
   screen: the whole step then reads as "scan this" and the field arrives as a
   surprise. Beside it, the two halves of one action are one picture and the eye
   goes left to right exactly as the instruction does. */
.cb-lock-scan {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--cb-space-4xl) var(--cb-space-5xl);
  margin-block-start: var(--cb-space-4xl);
  text-align: start;
}
.cb-lock-enter {
  display: grid;
  gap: var(--cb-space-lg);
  justify-items: center;
}
.cb-lock-label {
  margin: 0;
  font-size: var(--cb-type-sm-size);
  color: var(--cbc-ink-faint);
}
/* On its own light ground in both themes: a QR inverted for dark mode is one
   many phone cameras will not read, and the couple of seconds somebody spends
   failing to scan it is worse than the contrast against the plane. */
.cb-lock-square {
  padding: var(--cb-space-2xl);
  /* A hairline as well as a shadow, because in the light theme the plane behind
     this is very nearly the same white the square has to be: the shadow alone
     left a QR apparently floating on nothing, with no edge to say where the
     card it is printed on stops. */
  border: 1px solid var(--cbc-line);
  border-radius: var(--cb-radius-4xl);
  background: var(--cb-color-white);
  color: var(--cb-color-black);
  box-shadow: var(--cb-shadow-raised);
  /* Its wait is inside the keyframe for the reason the mark's is: a delay
     survives the console's own reduced-motion switch and a shaped opening does
     not. */
  animation: cbc-lock-square calc(var(--cb-motion-slow) + var(--cb-motion-base)) var(--cbc-spring);
}
/* Bigger than the 208 this used to be, because the panel it sits on is now the
   larger part of the screen rather than a 480 column. Composed the way --cbc-rail
   is: the scale has 160 and nothing between it and 320. */
/* `width` and not `inline-size`, which is the one place in this file the
   logical property is wrong. On an <svg> those two are geometry properties
   rather than aliases, so the physical one console-forms.css already writes
   wins whatever the specificity says, and the square came out at its old size
   with no rule anywhere to explain it. */
.cb-lock-square .cb-qr {
  width: calc(var(--cb-space-11xl) + var(--cb-space-8xl));
  height: calc(var(--cb-space-11xl) + var(--cb-space-8xl));
}
@keyframes cbc-lock-square {
  0%,
  38% {
    opacity: 0;
    transform: scale(0.94);
  }
}

/* ---- The key in letters ----
   Under both columns, because it is a way of doing the whole step rather than a
   caption on half of it. Folded away, because it is for the person who cannot
   use the square: somebody on a screen reader, somebody whose authenticator is
   on this same machine, somebody with no second device to point at it. Every
   product that offers only the square has a support queue about it. */
.cb-lock-manual {
  grid-column: 1 / -1;
  justify-self: center;
  text-align: center;
}
.cb-lock-manual > summary {
  cursor: pointer;
  font-size: var(--cb-type-sm-size);
  color: var(--cbc-ink-faint);
}
.cb-lock-manual > summary:hover {
  color: var(--cbc-ink);
}
.cb-lock-manual-body {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--cb-space-lg);
  margin-block-start: var(--cb-space-lg);
}
.cb-lock-manual-say {
  inline-size: 100%;
  margin: 0;
  font-size: var(--cb-type-sm-size);
  color: var(--cbc-ink-muted);
}
/* The secret itself is `.cb-manual-code`, which console-forms.css already owns
   and the profile screen already draws (views/code-dialog.ts). One class for
   one thing: what is set here is only the two values this surface wants
   different, a size up and a little tracking, because it is read off a screen
   and typed into a phone. */
.cb-lock-manual-body .cb-manual-code {
  font-size: var(--cb-type-sm-size);
  letter-spacing: var(--cb-tracking-xxs);
}

/* ---- The code on its own ----
   The verify screen, where there is no square and the six slots are the object.
*/
.cb-lock-solo {
  display: grid;
  gap: var(--cb-space-xl);
  justify-items: center;
  margin-block-start: var(--cb-space-4xl);
}
/* A short note about what happened, at the width of a short note. Stretched to
   the card it reads as a place to write an essay, which is not what is being
   asked for and not what anybody standing at a locked door wants to be asked
   for. The lede above it sets the measure; this follows it. */
.cb-lock-solo > textarea {
  inline-size: min(100%, var(--cb-space-11xl) * 3);
  resize: vertical;
}

/* ---- Ten recovery codes ----
   Two columns, tabular, in the console's mono. Ten in one column reads as a
   list somebody scrolls past; in two it reads as a set somebody copies. They
   land one after another off --i, which is the set being handed over rather
   than a block of text appearing. */
.cb-lock-vault {
  display: grid;
  gap: var(--cb-space-2xl);
  inline-size: 100%;
  max-inline-size: var(--cb-width-lg);
  margin: var(--cb-space-4xl) auto 0;
}
/* The block itself is `.cb-codes`, which console-forms.css owns and the profile
   screen already draws. What a full screen wants that a dialog does not is the
   room around them and an edge: the ten codes are the object on this card
   rather than a detail in a box, so they sit in a bordered block with real air
   in it. */
.cb-lock-vault .cb-codes {
  padding: var(--cb-space-3xl);
  gap: var(--cb-space-md) var(--cb-space-2xl);
  border: 1px solid var(--cbc-line);
  border-radius: var(--cb-radius-3xl);
}
/* Each code is `.cb-recovery-code`, console-forms.css's, so the set shown here
   and the fresh set the profile screen mints are the same object. A size up
   inside this block, and its place in the queue. */
.cb-lock-vault .cb-recovery-code {
  font-size: var(--cb-type-md-size);
  letter-spacing: var(--cb-tracking-xxs);
  animation: cbc-emerge var(--cb-motion-base) var(--cbc-spring) backwards;
  animation-delay: var(--cbc-step-fine);
}
.cb-lock-vault-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--cb-space-xl);
}
/* Two ways of doing the same thing, so they sit together and neither leads.
   The tick box across the row is still what this screen is asking for. */
.cb-lock-vault-acts {
  display: flex;
  align-items: center;
  gap: var(--cb-space-md);
}

/* The passkey button above the six slots, and the word that joins them.
   "or" rather than a rule, because these are two ways of doing one thing and a
   line would say they are two sections. The word is small and faint: it is
   punctuation, not a heading. */
.cb-lock-orkey {
  display: grid;
  justify-items: center;
  gap: var(--cb-space-lg);
  margin-block-end: var(--cb-space-lg);
}
/* The way out for somebody who has neither, under the card rather than beside
   the two real answers. Quiet on purpose: it is not a third way in, it is what
   to do when there is no way in, and at the weight of a button it would read
   as one more thing to try. */
.cb-lock-stuck {
  border: 0;
  padding: 0;
  background: none;
  cursor: pointer;
  font: inherit;
  font-size: var(--cb-type-xs-size);
  color: var(--cbc-ink-faint);
  text-decoration: underline;
  text-underline-offset: var(--cb-space-xxs);
  transition: color var(--cb-motion-fast) var(--cbc-spring);
}
.cb-lock-stuck:hover {
  color: var(--cbc-ink);
}

.cb-lock-orkey > span {
  font-size: var(--cb-type-xs-size);
  color: var(--cbc-ink-faint);
  text-transform: lowercase;
}

/* ---- Smaller windows, and shorter ones ----
   Two axes, because they fail differently, and console-ask.css already carries
   the argument: narrow, the type runs out of line length; short, there is
   nothing wrong with the type and everything wrong with the air around it. The
   picture, the frame's padding and the heading are all that sheet's; what is
   here is the four things this screen has of its own. */
/* 1024px mirrors tokens.breakpoint.lg */
@media (max-width: 1024px) {
  /* The square and the field stack, because there is no longer room not to.
     The picture is gone at this width too (console-ask.css), so the panel is
     the whole screen and the column has the width it needs. */
  .cb-lock-scan {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
  }
}
/* 640px mirrors tokens.width.lg, which is where six slots stop fitting */
@media (max-width: 640px) {
  .cb-lock-code {
    --lock-slot: var(--cb-space-7xl);
  }
  .cb-lock-slot {
    font-size: var(--cb-type-lg-size);
  }
  .cb-lock-vault .cb-codes {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* 1024px mirrors tokens.breakpoint.lg, on the other axis. A laptop advertised
   as 1440 by 900 hands a browser about eight hundred pixels once its own chrome
   is out of the way, so this is not the degraded layout, it is the ordinary
   one. The air gives way first and the mark comes down the scale with it. */
@media (max-height: 1024px) {
  /* THE MARK DOES NOT COME DOWN HERE, and it used to. This is the height of an
     ordinary laptop, the card it is on has one heading, one sentence and one
     button, and there were two hundred pixels of nothing under all of it: a
     128-pixel shield is not what runs a screen like that out of room. What does
     is the setting-up card, which has no mark at all. So the air closes up and
     the mark holds its size until the window is genuinely short. */
  .cb-lock-scan {
    margin-block-start: var(--cb-space-2xl);
  }
  .cb-lock-solo {
    margin-block-start: var(--cb-space-2xl);
  }
  .cb-lock-vault {
    margin-block-start: var(--cb-space-2xl);
  }
  .cb-lock-square {
    padding: var(--cb-space-lg);
  }
  .cb-lock-square .cb-qr {
    width: calc(var(--cb-space-11xl) + var(--cb-space-6xl));
    height: calc(var(--cb-space-11xl) + var(--cb-space-6xl));
  }
  .cb-lock-code {
    --lock-slot: var(--cb-space-7xl);
  }
  .cb-lock-acts {
    margin-block-start: var(--cb-space-2xl);
  }
}
/* 768px mirrors tokens.breakpoint.md, on the other axis */
@media (max-height: 768px) {
  .cb-lock-mark .cb-lock-glyph,
  .cb-lock-mark .cb-lock-ok {
    inline-size: var(--cb-space-5xl);
    block-size: var(--cb-space-5xl);
  }
  .cb-lock-square .cb-qr {
    width: var(--cb-space-11xl);
    height: var(--cb-space-11xl);
  }
  .cb-lock-code {
    --lock-slot: var(--cb-space-6xl);
  }
  .cb-lock-slot {
    font-size: var(--cb-type-lg-size);
  }
  .cb-lock-vault .cb-codes {
    padding: var(--cb-space-xl);
    gap: var(--cb-space-sm) var(--cb-space-xl);
  }
  .cb-lock-vault .cb-recovery-code {
    font-size: var(--cb-type-sm-size);
  }
  .cb-lock-acts .cb-btn {
    padding: var(--cb-space-md) var(--cb-space-4xl);
  }
}
/* 560px mirrors tokens.width.md, on the other axis, the same way the width
   query above mirrors width.lg.

   AND NOW THE MARK COMES DOWN AGAIN, because at this height it is the biggest
   thing on the screen and it is the only thing on it that is decoration. The
   offer card measured twenty-six pixels over its window at 480 with everything
   else already closed up, and ninety-six of those pixels were a drawing of a
   shield. Sixty-four still reads as a mark rather than an icon, and it is the
   difference between a screen somebody scrolls and a screen somebody answers.

   The lockup at the top of the plane is untouched here, as it is at every other
   rung: that one is the identity carried across from the sign-in door, and it
   holds its size (console-ask.css says why at length). This is not that. */
@media (max-height: 560px) {
  .cb-lock-mark .cb-lock-glyph,
  .cb-lock-mark .cb-lock-ok {
    inline-size: var(--cb-space-4xl);
    block-size: var(--cb-space-4xl);
  }
  .cb-lock-acts {
    margin-block-start: var(--cb-space-xl);
  }
  /* The code screen's own row of slots, one step down. Six 48-pixel boxes and
     the air above them are most of what is left on that card once the mark has
     come down, and a 40-pixel slot is still a target twice the size of the
     type in it. */
  .cb-lock-solo {
    margin-block-start: var(--cb-space-lg);
  }
  .cb-lock-code {
    --lock-slot: var(--cb-space-5xl);
  }
  .cb-lock-slot {
    font-size: var(--cb-type-md-size);
  }
}
/* 480px mirrors tokens.breakpoint.sm, on the other axis, and it is the last
   rung there is. The code screen is the tallest card this flow has: a mark, a
   heading, a sentence, six slots and a footnote, and at 480 it was still
   eighteen pixels over with everything else already closed up. The mark takes
   the last step, to the size the lockup at the top of the plane is drawn at,
   which is as small as a mark can go and still be one.

   NOTHING PRESSABLE SHRINKS HERE, and that is deliberate: Back and Not now stay
   at their full height, because 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 card that scrolls. */
@media (max-height: 480px) {
  .cb-lock-mark .cb-lock-glyph,
  .cb-lock-mark .cb-lock-ok {
    inline-size: var(--cb-space-3xl);
    block-size: var(--cb-space-3xl);
  }
  .cb-lock-solo {
    gap: var(--cb-space-lg);
  }
}
