/* ---- Settling in: the profile stop ----

   The screen is a sentence and the sentence is the control. Two words in it are
   changeable and both are underlined to say so; the picture is set into the
   line in front of them. src/onboarding/step-profile.ts argues why at length.

   EVERYTHING HERE HANGS OFF `.cb-say`, which is the block `made()` returns into
   the card's own slot. It sits inside the questions' room and inherits its
   ground, its measure and its footer, so nothing in this file paints a plane,
   a panel or a background: it draws one sentence and the mark above it.

   Every colour is a --cbc-* semantic and every length is off the token scale,
   with the two exemptions the guard already names: hairlines, and the path data
   further down, which is geometry rather than a measurement. */

/* THE PAGE IS CENTRED, WHICH IS THE SECOND STEP'S SHAPE AND NOT A QUESTION'S.
   A question is a heading with a column of answers under it and reads down the
   left edge; these two stops are one object in the middle of a plane, the way
   the lock next door is (console-gate.css `.cb-lock-page` says the same thing
   in one line).

   KEYED ON THE MARK, which is the fact that actually separates them. It was
   keyed on the sentence, and the sentence is only on the first of the two: the
   profile stop centred and the team stop beside it did not, so one run had two
   layouts. Every card with a mark is one of these stops and no question has
   one, so page.ts stamps the page and this reads it. */
.cb-ask-page[data-mark] {
  text-align: center;
}
.cb-ask-page[data-mark] .cb-ask-title,
.cb-ask-page[data-mark] .cb-ask-lede,
.cb-ask-page[data-mark] .cb-ask-eyebrow {
  text-align: center;
}
/* The standfirst holds a measure of its own, or a centred paragraph runs the
   full width of the plane and stops being a paragraph. The lock's own rule. */
.cb-ask-page[data-mark] .cb-ask-lede {
  max-inline-size: var(--cb-width-lg);
  margin-inline: auto;
}
/* And the button goes to the middle with them. Its own rule pushes it to the
   end with an auto margin, which is right on a card that reads down the left.

   AND IT KEEPS THE WIDTH OF ITS OWN WORDS ON A SHORT WINDOW. console-ask.css
   takes the button to the full measure under 768 tall, which is right where it
   was written: a question at that height is a column of taps and a button the
   width of its own words at the end of that column is a small target beside
   four large ones. There is no such column here, so what that rule produced was
   a pill eight hundred pixels wide with two words in the middle of it. */
.cb-ask-page[data-mark] .cb-ask-next {
  margin-inline: auto;
  inline-size: fit-content;
}

.cb-say {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--cb-space-2xl);
  text-align: center;
}

/* ---- The mark: a signature being written ----

   THE GESTURE IS LEFT TO RIGHT AND IT HAS A TRAVELLING PART, which is the whole
   of what makes it not the second step's shield. That mark draws a perimeter
   and places a thing inside it, because a second factor is a boundary closing
   around something. This one writes a name, because that is what this stop is,
   and it ends where a hand lifts rather than where a shape closes.

   THREE BEATS OUT OF ONE ICON. lucide's `signature` is two paths: the rule, and
   the name on it. The rule sweeps in first, the name is written on it second,
   and the pen that wrote it lifts away third. Nothing here is hand-drawn, which
   is docs/10's rule and also the reason this is short: the drawing is the
   icon's, and all this file decides is the order.

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

   THIS IS THE SECOND STEP'S OWN CONSTRUCTION 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 the whole mark is one animation with four voices rather than four
   animations that happen to have been given 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, which is arriving on its own stagger at the same
   moment (console-ask.css `.cb-ask-page > *`). So the signature started drawing
   while the box holding it was still travelling: two gestures over one object,
   neither of them finished, which is exactly the "not Apple-like" of it. Waits
   inside the keyframes mean the first tenth of the clock is a hold, the card
   lands inside that hold, and the drawing starts on a mark that has arrived.

   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. 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 rule sweeps 278 to 470, the name is written 470 to 1590, the nib
   travels 374 to 1702, and the settle runs 1526 to the end at 1750. */
/* THE BOX IS `.cb-page-mark` IN console-ask.css and only what this mark IS lives
   here. The size, the height ladder, the air under it, the colour, the centring
   and the half a unit of stroke were written out in this file, in the second
   step's file and in the team stop's file, three times and three different
   ways: on an ordinary laptop the shield drew at 128, this at 96 and the team's
   pair at 64, with sixteen pixels of air under the first, NONE under this one
   and twelve under the third. Pressing "That is me" therefore made the biggest
   thing on the screen change size, weight and position while every band under
   it cross-faded. One box, three drawings.

   THE SIZING OF THE ICON MUST STAY A DIRECT-CHILD RULE, and that is the whole
   of a bug worth remembering. This file used to say `.cb-say-mark .cb-icon {
   inline-size: 100% }`, and `icon()` puts `cb-icon` on the PEN as well as on
   the signature (dom.ts). Two classes beat the one on `.cb-say-nib` whatever
   the order, so the nib was sized at 100% of its own track: a pen drawn at the
   full width of the mark, sweeping across the signature it was supposed to be
   writing, for the whole of --cbc-mark-run. The shared rule uses `>` and the
   nib is a grandchild, so it keeps the size written for it below. */
.cb-say-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, while the heading under it was still held
     invisible. */
  --mark-settle: cbc-say-settle;
}

/* THE RULE FIRST, because it is the thing the name is written on and paper
   arrives before ink. `M3 21h18` is the second path in the file; matched by
   position rather than by a 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 draws, in the wrong order, which is visible immediately
   and cannot be silent. */
.cb-say-ink svg path:nth-of-type(2) {
  stroke-dasharray: 20;
  animation: cbc-say-rule var(--cbc-mark-run) var(--cb-motion-ease) var(--mark-in, 0s) both;
}
/* AND THE NAME ON IT, once there is something to write on. 60 is the squiggle's
   own length rounded comfortably up, which is the same trick the shield uses:
   one number covers a path whose exact length nobody here has to know.

   THE OFFSET IS NEGATIVE, AND THAT IS THE WHOLE OF WHICH WAY IT WRITES. A dash
   offset animated from +length reveals a path from its START; from -length it
   reveals from the END. lucide draws this signature beginning at the little
   tail on the right, so the first version wrote that tail, then travelled left
   into the loop, then came back right for the flourish: a hand moving in three
   directions, ending in the middle, which is what "drawn backwards" looks like.

   Reversed, it opens on the top of the flourish where a capital starts, sweeps
   down and left through the loop, and finishes on the tail flicking off to the
   right, which is where a hand actually leaves the paper. */
.cb-say-ink svg path:nth-of-type(1) {
  stroke-dasharray: 60;
  animation: cbc-say-ink var(--cbc-mark-run) var(--cbc-hand) var(--mark-in, 0s) both;
}

/* ---- The pen that is writing it ----

   IT RIDES THE SIGNATURE'S OWN PATH. `offset-path` is handed the same path data
   the squiggle is drawn from, so the nib is never a few pixels off the ink: one
   path, and both the drawing and the thing drawing it derived from it.

   THE COPY IS THE ONE THING IN THIS FILE THAT CAN GO STALE, and it is worth
   saying plainly. CSS cannot read a path out of an imported SVG, so this is the
   only way for the two to share one. If the icon package ever redraws
   `signature`, the ink will follow it and the pen will not, and what that looks
   like is a pen writing beside its own line rather than on it. Visible in one
   glance, which is the most that can be arranged.

   THE COORDINATES ARE THE ICON'S, WHICH IS WHY THE BOX IS SCALED. A path can
   only be ridden in the units it was written in, and this one is written in a
   24-unit viewBox. So the track is 24 across and multiplied up to the mark's
   own size; the alternative is rewriting every number in the path by hand
   against a size somebody is free to change.

   `offset-rotate: 0deg` on purpose: a nib that turned to follow the tangent
   would spin twice through the flourish, which reads as a pen being dropped. */
.cb-say-track {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: var(--cb-space-3xl);
  block-size: var(--cb-space-3xl);
  /* Off the mark's own size rather than off a length written here, so the pen
     follows the ladder in console-ask.css instead of needing a rung of its own
     in this file for every rung in that one. */
  --sign-grid: calc(var(--mark-size) / var(--cb-space-3xl));
  transform: scale(var(--sign-grid));
  transform-origin: 0 0;
  pointer-events: none;
}
.cb-say-nib {
  position: absolute;
  inline-size: var(--cb-space-lg);
  block-size: var(--cb-space-lg);
  offset-path: path(
    "m21 17-2.156-1.868A.5.5 0 0 0 18 15.5v.5a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1c0-2.545-3.991-3.97-8.5-4a1 1 0 0 0 0 5c4.153 0 4.745-11.295 5.708-13.5a2.5 2.5 0 1 1 3.31 3.284"
  );
  offset-rotate: 0deg;
  offset-anchor: 0% 100%;
  animation: cbc-say-nib var(--cbc-mark-run) var(--cbc-hand) var(--mark-in, 0s) both;
}
/* THE NIB CARRIES ITS OWN WEIGHT, because it is the one part of this mark that
   is not drawn at the mark's size. It is twelve units inside a track scaled by
   mark/24, so it renders at half the mark: a stroke of 1 there lands at the
   same rendered thickness as the half a unit everything else on this surface is
   drawn at (console-ask.css `.cb-page-mark svg`). It was 2, which is twice the
   weight of the line it is supposed to be leaving behind it. */
.cb-say-nib svg {
  stroke-width: 1;
}

@keyframes cbc-say-rule {
  0%,
  8% {
    stroke-dashoffset: 20;
  }
  20%,
  100% {
    stroke-dashoffset: 0;
  }
}
/* SEVEN TENTHS OF THE CLOCK, WHICH IS MOST OF IT, and it was half. The name is
   the only thing on this mark anybody is actually watching, and it was being
   written in six hundred milliseconds on a curve that spent two hundred of them
   arriving. Given the room, and given a hand's curve rather than a panel's, it
   reads as somebody signing rather than as a line being wiped on. */
@keyframes cbc-say-ink {
  0%,
  20% {
    stroke-dashoffset: -60;
  }
  90%,
  100% {
    stroke-dashoffset: 0;
  }
}
/* The nib waits on the paper, writes, and lifts. It runs from 100 to 0 because
   the INK does: the squiggle is revealed from the end of its path, so a nib
   travelling from the start would be a pen moving one way and a line appearing
   the other, crossing in the middle and meeting nowhere. */
@keyframes cbc-say-nib {
  0%,
  14% {
    offset-distance: 100%;
    opacity: 0;
  }
  20% {
    offset-distance: 100%;
    opacity: 1;
  }
  90% {
    offset-distance: 0%;
    opacity: 1;
  }
  97%,
  100% {
    offset-distance: 0%;
    opacity: 0;
  }
}
/* AND THE WHOLE MARK TAKES THE WEIGHT OF THE PEN LEAVING THE PAPER. One settle,
   three per cent, on the frame the flourish finishes. The second step does the
   same thing as its outline meets itself, and for the same reason: nothing else
   on the screen is moving, so it reads as the object being finished rather than
   as an element animating. */
@keyframes cbc-say-settle {
  0%,
  86% {
    transform: scale(1);
  }
  93% {
    transform: scale(1.03);
  }
  100% {
    transform: scale(1);
  }
}

/* ---- The sentence ----

   BIG, BUT NOT AS BIG AS THE GREETING ABOVE IT. The card's own title is 48 and
   says hello by name; this is the thing being agreed with, and two blocks at
   one size would be two headings arguing. `text-wrap: balance` because a
   sentence with two underlined words in it breaks badly on its own: left to the
   browser, one of the two lands alone on the last line and reads as a stray. */
/* NOTHING ABOUT THE TYPE IS SET HERE, and that is the point of it being the
   heading rather than a paragraph under one. It sits inside `.cb-ask-title`, so
   it is 48 on a tall window and steps down with every other heading on this
   surface through the ladder console-ask.css already runs (the second step's
   own title uses it). A size written here would be a fourth rung nobody
   maintains.

   `display: block` because it is a `<span>` inside the h1: the picture and the
   two slots inside it are inline, and the balance below only applies to a block
   container. */
.cb-say-line {
  display: block;
  /* WIDER THAN THE CARD'S OWN MEASURE, because this is not a paragraph. A
     measure is for prose somebody reads down; this is two lines somebody reads
     across, and holding them to a reading measure broke each of them again in
     the middle. Balance comes off with it: the two lines are written as two
     (step-profile.ts), so there is nothing left for the browser to balance and
     leaving it on would only fight the composition. */
  max-inline-size: var(--cb-width-3xl);
  margin-inline: auto;
}
/* One line of the sentence. Block so the break is the composition rather than
   whatever the measure happened to do with the length of somebody's name. */
.cb-say-row {
  display: block;
}
.cb-say-words {
  color: var(--cbc-ink-muted);
}
/* PUNCTUATION NEVER STARTS A LINE. The sentence wraps wherever it must, and
   left alone the comma after the name and the full stop after the zone are the
   two places it would rather break: a line beginning ", and count my days"
   reads as a typo. Each is glued to the word it belongs to and the break moves
   to the space after it, which is where a break belongs. */
.cb-say-clause {
  white-space: nowrap;
}

/* ---- The picture, set into the line ----

   IN THE SENTENCE RATHER THAN ABOVE IT, which is the difference between a
   profile and a form. It is the first thing on the first line, at the size of a
   face, and pressing it opens the file chooser exactly as the row it replaces
   did (face-control.ts is unchanged; only where it is drawn moved).

   `vertical-align` rather than a flex row, because the disc has to sit on the
   sentence's own baseline: a flex row would centre it against the whole line
   box and leave it floating a few pixels high on any line that wraps. */
.cb-say-face {
  display: inline-block;
  /* ALIGNED TO THE TYPE, NOT TO THE LINE BOX. `middle` centres a box on the
     line's own middle, and a line box at this size carries the room a descender
     and the slot's underline need underneath it: the disc came out sitting low,
     centred on space that has nothing in it. Aligned to the cap instead, by
     eye, so it sits with the letters rather than with the leading.

     A hairline-scale nudge, which is the token guard's own exemption: it is
     correcting for the difference between a cap height and a line height, and
     that is not a value off the spacing scale. */
  vertical-align: middle;
  transform: translateY(-3px);
  margin-inline-end: var(--cb-space-lg);
}
/* NOT `display: contents` ANY MORE. The cross in the corner of the face is
   positioned against this box (console-ask-form.css), and a box that generates
   no box of its own is not a containing block: the cross went looking for the
   nearest positioned ancestor and landed on the sentence. Inline-block keeps it
   out of the sentence's flow and gives the cross something to hold on to. */
.cb-say-face .cb-pic-set {
  display: inline-block;
  gap: 0;
}
/* THE CROSS RIDES THE DISC AT THIS SIZE, and it needs nothing said here to do
   it. Its own rule pins it to the top END corner of the set, which on this
   surface is the top right of the face, because the sentence is centred and the
   disc is the whole set. This block used to move it there from the start corner
   and no longer has to: the shuffle took the start corner everywhere, so the
   two agree without a surface override (console-face.css). */
/* The row the picture control returns is a full-width answer row on the stop it
   was built for. Here it is a disc in a sentence, so everything the row draws
   comes off and what is left is the face and the mark over it. */
.cb-say-face .cb-pic {
  display: inline-flex;
  padding: 0;
  border: 0;
  background: none;
  border-radius: var(--cb-radius-full);
}
/* THE CAMERA IS PINNED TO THE DISC AND THE DISC HAS TO SAY SO. `.cb-pic-over`
   is absolute, and on the row this control was built for its containing block
   is the chip around the face. Stripping the row's own layout off above left
   the chip static, so the mark went looking for the nearest positioned
   ancestor and landed under the sentence. */
.cb-say-face .cb-ask-chip-face {
  position: relative;
}
.cb-say-face .cb-pic .cb-ask-words {
  display: none;
}
.cb-say-face .cb-ask-chip-face,
.cb-say-face .cb-avatar {
  inline-size: var(--cb-space-7xl);
  block-size: var(--cb-space-7xl);
  font-size: var(--cb-type-lg-size);
}

/* ---- The two changeable words ----

   UNDERLINED, AND THE UNDERLINE IS THE AFFORDANCE. There is no box, no chevron
   sitting in the type and no label: what says these two are yours to change is
   that they are the only underlined words in the sentence, and that the line
   answers when the pointer arrives (rule 14: hover answers immediately and
   never moves layout, which is why this is a border rather than a size change).

   Two pixels because an underline under 30-pixel type is a hairline by any
   other name, which is the token guard's own exemption. */
.cb-say-slot {
  color: var(--cbc-ink);
  font-weight: var(--cb-font-weight-semibold);
  border-block-end: 2px solid var(--cbc-line);
  transition: border-color var(--cb-motion-fast) var(--cb-motion-ease);
}
.cb-say-slot:hover,
.cb-say-slot:focus-within {
  border-block-end-color: var(--cbc-accent);
}

/* THE NAME IS A REAL INPUT WITH THE BOX TAKEN OFF, and it sizes itself to what
   is in it. The input and a hidden copy of its value are stacked in one inline
   grid cell: the copy is what the browser measures, at the same font and size,
   and the input stretches to the cell. It is the one way to size a text control
   to its own content that does not involve measuring glyphs by hand.

   `white-space: pre` on the copy so a trailing space somebody typed still
   counts, and `min-inline-size` so an empty field is a slot rather than a gap. */
.cb-say-slot-name {
  display: inline-grid;
  /* Enough that an empty field is a slot rather than a gap, and no more: the
     sizer below is what actually decides the width. */
  min-inline-size: var(--cb-space-9xl);
}
/* AND THE INPUT MUST NOT HAVE AN OPINION ABOUT ITS OWN WIDTH. A text input's
   intrinsic size is its `size` attribute, which defaults to twenty characters:
   at 48-pixel type that is five hundred pixels of grid column, so the slot came
   out three times the width of the word in it with the underline running off
   into the sentence. `size="1"` in the markup is what makes the copy behind it
   the only thing left to measure (step-profile.ts). */
.cb-say-name {
  min-inline-size: 0;
}
.cb-say-slot-name > * {
  grid-area: 1 / 1;
  font: inherit;
  letter-spacing: inherit;
}
.cb-say-name {
  inline-size: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  text-align: center;
  border-radius: var(--cb-radius-xs);
}
.cb-say-name::placeholder {
  color: var(--cbc-ink-faint);
}
.cb-say-name:focus {
  outline: none;
}
.cb-say-name:focus-visible {
  outline: none;
}
.cb-say-sizer {
  visibility: hidden;
  white-space: pre;
  pointer-events: none;
}

/* THE ZONE IS THE CONSOLE'S OWN MENU WITH THE SAME BOX TAKEN OFF. It stays a
   real `<select>`, which is what gives it the platform's own picker on a phone
   and its own keyboard on a laptop; all this does is stop it looking like a
   field in a form. The chevron goes with the box: in a sentence it is a piece
   of furniture between two words. */
/* ---- The zone picker ----

   THE WORD, AND A POPOVER WITH A SEARCH BOX IN IT. It was a native `<select>`
   holding every time zone the browser knows, which is the right control for six
   options and the wrong one for four hundred: it opened as a column the height
   of the screen, it could not be searched past the platform's first-letter
   jump, and on this surface it inherited the sentence's own type, so the list
   came out at forty-eight pixels a row. src/onboarding/zone-picker.ts argues it
   in full; this draws it.

   THE POPOVER IS IN THE TOP LAYER and is positioned from two custom properties
   the picker measures and writes, because a `position: fixed` box in the top
   layer has no ancestor to be fixed against: the viewport is all there is, and
   the opener's own rectangle is the only thing that knows where it should be.

   Its type is the console's, NOT the sentence's. The word in the sentence is a
   heading; the list is a list, and it is set at the size every other menu in
   this console is set at (which is the whole bug the native one had). */
.cb-zone-word {
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
/* A BUTTON, NOT A FIELD, which is what made this one costly. The five other
   elements in this console that drop their outline are inputs and textareas,
   where the caret is the affordance and removing the ring loses nothing. This
   is a <button role="combobox"> dressed as a word in a sentence, so there is no
   caret, and `outline: none` removed the only sign a keyboard had ever reached
   it. The word looked identical focused and unfocused, and the menu it opens
   is reachable no other way.
   Kept off for the pointer and put back for the keyboard, which is what
   :focus-visible is for. The radius is the small step: the ring hugs one word
   set in a running sentence, and a square corner on it reads as a table cell. */
.cb-zone-word:focus {
  outline: none;
}
.cb-zone-word:focus-visible {
  outline: var(--cbc-focus);
  outline-offset: var(--cbc-focus-gap);
  border-radius: var(--cb-radius-xs);
}

/* ---- CLOSED MEANS CLOSED, AND THIS RULE IS THE WHOLE REASON IT DOES ----

   A popover is hidden by the browser's own stylesheet, with
   `[popover]:not(:popover-open) { display: none }`. That rule lives in the USER
   AGENT origin, and an author rule beats a user agent rule whatever the
   specificity says: a bare `display: flex` on this class silently overrode it,
   so the list was drawn at all times.

   What that looked like is worth writing down, because it does not look like a
   styling mistake. `hidePopover()` worked perfectly: the element left the top
   layer, `:popover-open` went false, every close path ran. And the list stayed
   on the screen, no longer in the top layer, no longer answering its own
   presses, until the page was reloaded. Stuck, for a reason nothing about it
   pointed at.

   It also passed a test. The test asked `matches(":popover-open")`, which was
   correctly false, and reported that the popover had closed. Ask whether a box
   HAS SIZE, not whether a flag says it should not.

   So the layout is stated for the open state only, and the closed state is left
   to the browser. */
.cb-zone-pop {
  display: none;
}
.cb-zone-pop:popover-open {
  position: fixed;
  inset: auto;
  inset-inline-start: var(--zone-x);
  inset-block-start: var(--zone-y);
  margin: 0;
  padding: 0;
  inline-size: var(--cb-width-xs);
  /* WHAT THE SIDE IT OPENED ON ACTUALLY HAS. The picker measures the room above
     and below the word and writes the larger of the two here, so the list is
     never taller than the space it is standing in. A fixed maximum was what put
     the first version's top off the screen. */
  max-block-size: min(var(--zone-room, 60vh), var(--cb-width-md));
  display: flex;
  flex-direction: column;
  border: 1px solid var(--cbc-line);
  border-radius: var(--cb-radius-2xl);
  background: var(--cbc-raised);
  box-shadow: var(--cbc-shadow);
  overflow: hidden;
  /* The console's own type, at the console's own size. */
  font-size: var(--cb-type-base-size);
  line-height: var(--cb-type-base-line-height);
  letter-spacing: normal;
  font-weight: var(--cb-font-weight-regular);
  color: var(--cbc-ink);
  /* A list opening out of a word is a thing appearing beside it, so it arrives
     from the edge it is attached to rather than from nowhere. */
  animation: cbc-zone-open var(--cb-motion-fast) var(--cbc-spring);
}
/* FLIPPED WHERE THERE IS NO ROOM UNDER IT, which on this screen is most
   windows: the sentence sits in the middle of the plane and the list is taller
   than the half below it. Translated rather than given a different inset, so
   the picker writes one number either way. */
.cb-zone-pop:popover-open[data-above] {
  transform: translateY(-100%);
  transform-origin: bottom left;
}
@keyframes cbc-zone-open {
  from {
    opacity: 0;
    transform: translateY(calc(var(--cb-space-sm) * -1));
  }
}
.cb-zone-pop:popover-open[data-above] {
  animation-name: cbc-zone-open-up;
}
@keyframes cbc-zone-open-up {
  from {
    opacity: 0;
    transform: translateY(calc(-100% + var(--cb-space-sm)));
  }
  to {
    opacity: 1;
    transform: translateY(-100%);
  }
}

/* ---- The search box ----
   Pinned, because the list under it scrolls and a search box that scrolled away
   would be a search box you have to scroll back to in order to correct. */
.cb-zone-search {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--cb-space-md);
  padding: var(--cb-space-lg) var(--cb-space-xl);
  border-block-end: 1px solid var(--cbc-line);
  color: var(--cbc-ink-faint);
}
.cb-zone-search .cb-icon {
  flex: none;
  inline-size: var(--cb-space-xl);
  block-size: var(--cb-space-xl);
}
.cb-zone-find {
  flex: 1;
  min-inline-size: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--cbc-ink);
  font: inherit;
}
.cb-zone-find:focus {
  outline: none;
}
.cb-zone-find::placeholder {
  color: var(--cbc-ink-faint);
}

.cb-zone-list {
  flex: 1;
  min-block-size: 0;
  overflow-y: auto;
  padding: var(--cb-space-sm);
}
.cb-zone-group {
  padding: var(--cb-space-md) var(--cb-space-lg) var(--cb-space-xs);
  font-size: var(--cb-type-xs-size);
  line-height: var(--cb-type-xs-line-height);
  font-weight: var(--cb-font-weight-semibold);
  letter-spacing: var(--cb-tracking-xxs);
  text-transform: uppercase;
  color: var(--cbc-ink-faint);
}
/* ONE ROW, AND THE POINTER AND THE KEYBOARD LIGHT IT THE SAME WAY. `data-on` is
   written by the picker as the arrows move; hover paints the same ground, so a
   reader who starts with the mouse and finishes with the keyboard is never
   looking at two different kinds of highlight at once. */
.cb-zone-row {
  inline-size: 100%;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--cb-space-lg);
  padding: var(--cb-space-md) var(--cb-space-lg);
  border: 0;
  border-radius: var(--cb-radius-lg);
  background: none;
  color: var(--cbc-ink);
  font: inherit;
  text-align: start;
  cursor: pointer;
}
.cb-zone-row:hover,
.cb-zone-row[data-on] {
  background: var(--cbc-hover);
}
.cb-zone-row[aria-selected="true"] .cb-zone-city {
  color: var(--cbc-accent-text);
}
.cb-zone-city {
  font-weight: var(--cb-font-weight-medium);
}
.cb-zone-full {
  flex: none;
  font-size: var(--cb-type-xs-size);
  color: var(--cbc-ink-faint);
}
.cb-zone-none {
  padding: var(--cb-space-xl);
  color: var(--cbc-ink-faint);
  text-align: center;
}
.cb-zone-none[hidden] {
  display: none;
}

/* The word is a button now and it is the width of the word in it, so the slot
   is simply a slot: the stacking trick that used to size a native select from a
   hidden copy of its own label went with the select (zone-picker.ts). */
/* THE ZONE'S UNDERLINE, SAID AGAIN HERE, AND IT HAS TO BE SAID AGAIN.

   `.cb-say-slot` above puts a two-pixel rule under both changeable words, which
   is the only thing telling a reader they are changeable. The zone is a button
   wearing `.cb-zone-word`, and that class says `border: 0` because a button
   arrives with one: same specificity, later in this file, so it won. The rest
   at rest had no underline while the HOVER rule kept working, because a
   pseudo-class outranks it, so the word grew a line when you approached it and
   had none the moment you looked away. That is the affordance backwards.

   Restated on the zone's own class, which is later still. Not by making
   `.cb-zone-word` keep its border: that class is the picker, and the picker is
   also used where there is no sentence to underline. */
.cb-say-slot-zone {
  display: inline-block;
  border-block-end: 2px solid var(--cbc-line);
}
.cb-say-slot-zone:hover,
.cb-say-slot-zone:focus-within {
  border-block-end-color: var(--cbc-accent);
}

/* ---- The three quiet lines under it ----
   The clock the zone produces, the way back to a picture, and anything the
   server refused. All three are footnotes to the sentence and none of them ever
   holds space it is not using. */
/* UNDER THE WORD, NOT UNDER THE CARD. The block above centres everything in
   it, which put this line in the middle of the card while the zone it is about
   sat wherever the words before it happened to end. The shift is measured and
   written by say-clock.ts; nought is the old behaviour, and the fallback here
   is what a browser gets before the first frame and if the measure ever fails. */
.cb-say-clock {
  font-size: var(--cb-type-sm-size);
  line-height: var(--cb-type-sm-line-height);
  color: var(--cbc-ink-faint);
  transform: translateX(var(--cb-say-clock-shift, 0));
  transition: transform var(--cb-motion-base) var(--cbc-spring);
}
.cb-say-aside:empty,
.cb-say-refused:empty {
  display: none;
}
.cb-say-refused {
  font-size: var(--cb-type-sm-size);
  line-height: var(--cb-type-sm-line-height);
  color: var(--cbc-poor-text);
  max-inline-size: var(--cb-width-md);
}

/* ---- Short windows ----
   The same ladder the rest of this surface climbs, on the same rungs, with the
   air going first and the sentence last. The mark is the largest thing here and
   it is decoration, so it is what gives way; the sentence holds its size until
   the window genuinely cannot take it, which is the argument console-ask.css
   makes about its own heading. */
/* 1024px mirrors tokens.breakpoint.lg, on the height axis */
@media (max-height: 1024px) {
  .cb-say {
    gap: var(--cb-space-xl);
  }
}
/* 768px mirrors tokens.breakpoint.md, on the height axis */
@media (max-height: 768px) {
  .cb-say {
    gap: var(--cb-space-lg);
  }
  .cb-say-face .cb-ask-chip-face,
  .cb-say-face .cb-avatar {
    inline-size: var(--cb-space-6xl);
    block-size: var(--cb-space-6xl);
  }
}
