/* Campus Ride — one column, phone first, white.
 *
 * Black on white, the way Uber's app actually is: the ground is white, the one
 * primary action on a screen is a solid black fill, and colour is spent only
 * where it carries a meaning no word could carry faster.
 *
 * Four lamps, one job each, and nothing else is allowed to be coloured:
 *   amber  — pending YOUR action, or live right now
 *   green  — confirmed
 *   blue   — a human has checked who this person is
 *   red    — one tap from something irreversible
 *
 * Amber used to be the brand colour AND the primary button AND the live state
 * at once, which is why none of the three registered. It is the pending lamp
 * only now; black took the button, and the brand mark is monochrome.
 *
 * A lamp needs two values on white, not one. Amber and green are perfectly
 * legible as a FILL with dark text on them and illegible as text on white
 * (#FFC043 on white is 1.7:1), so each has a `-solid` for fills and a darkened
 * base for text and hairlines. Using one value for both is how the pending
 * pill ends up unreadable in daylight, which is the light this app is used in.
 *
 * Every number read out loud at a kerb is set in a monospaced face.
 */

.cr {
	/* Ground. White, with a single light grey for anything recessed — the tile
	   colour behind Uber's search bar, chips and account rows. */
	--bg:          #ffffff;
	--surface:     #ffffff;
	--sunken:      #f2f2f3;
	--line:        #e6e6e7;
	--line-strong: #c4c6c8;

	--text:   #000000;
	--text-2: #56585c;
	--text-3: #85888c;

	/* The primary action. One per screen, and it is the loudest object in the
	   system precisely because it is the only black fill on it. */
	--pri:       #000000;
	--pri-ink:   #ffffff;
	--pri-hover: #26282b;

	/* Pending your action, or live right now. Uber's yellow as the fill; a
	   darkened amber for text and edges, which the fill cannot do on white. */
	--signal:       #96620a;
	--signal-solid: #ffc043;
	--signal-ink:   #241800;
	--signal-tint:  rgba(255,192,67,.20);
	--signal-edge:  rgba(214,155,25,.55);

	/* Confirmed, and only confirmed. Uber's green. */
	--go:       #1c7c4d;
	--go-solid: #3aa76d;
	--go-ink:   #ffffff;
	--go-tint:  rgba(58,167,109,.13);
	--go-edge:  rgba(58,167,109,.45);

	/* One meaning: a human checked this person's ID. Nothing else, ever. Uber's
	   blue clears 4.4:1 on white, so it needs no second value. */
	--trust:      #276ef1;
	--trust-tint: rgba(39,110,241,.10);
	--trust-edge: rgba(39,110,241,.40);

	/* Never at rest — only on the second, confirming tap. Uber's red. */
	--alert:      #c93a2b;
	--alert-tint: rgba(212,67,51,.09);
	--alert-edge: rgba(212,67,51,.35);

	/* A map symbol, not a UI colour. Survives all four tile styles. */
	--route: #5b5bf0;

	--r-ctl:  12px;
	--r-card: 16px;
	--r-sm:   8px;
	--r-pill: 999px;

	/* Legacy aliases. Older markup and any stray rule still referring to
	   --accent keeps working instead of falling back to unstyled. */
	--accent:  #ffc043;
	--accent2: #f0ad25;
	--danger:  #d44333;
	--card:    #ffffff;
	--muted:   #56585c;
	--radius:  16px;

	--font-ui:   -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
	--font-data: ui-monospace, "SF Mono", "Cascadia Mono", "Roboto Mono", Menlo, Consolas, monospace;

	background: var(--bg);
	color: var(--text);
	font: 16px/1.55 var(--font-ui);
	min-height: 70vh;
	padding: 18px 14px 52px;
	box-sizing: border-box;
}

.cr *,
.cr *::before,
.cr *::after { box-sizing: border-box; }

/* The host theme styles headings, buttons and form controls globally, and on
   Woostify that turns the card headings a washed out grey against the dark
   card. Take them back explicitly rather than hoping the cascade wins. */
.cr h1,
.cr h2,
.cr h3 {
	color: var(--text);
	font-family: inherit;
	text-transform: none;
	letter-spacing: -.02em;
}

/* Not amber. A link is not a pending action, and letting it wear the pending
   lamp is exactly how amber stopped meaning anything. */
.cr a { color: var(--text); }

.cr button,
.cr input,
.cr select,
.cr textarea {
	font-family: inherit;
	line-height: 1.4;
	text-transform: none;
	letter-spacing: normal;
}

/* Every number said out loud or checked against reality. Tabular so 4729 can
   never be misread as 4720 at arm's length in the dark. */
.cr-d,
.cr-pin b,
.cr-karma b,
.cr-facts b,
.cr-plate {
	font-family: var(--font-data);
	font-variant-numeric: tabular-nums;
	letter-spacing: -.02em;
}

.cr-boot { color: var(--text-2); text-align: center; padding: 60px 0; }

.cr-wrap { max-width: 460px; margin: 0 auto; }

/* ------------------------------------------------------------------ chrome */

/*
 * Persistent and close to invisible. The mark sits top left and nothing else
 * competes with it; anything global goes in the right slot as a single control,
 * never a row of them. Sign out used to live here on every screen in the app —
 * it is an Account row now, and only screens with no tab bar to reach Account
 * from still carry it.
 */
.cr-top {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	min-height: 34px;
	padding-bottom: 10px;
	margin-bottom: 14px;
}

.cr-brand {
	display: flex;
	align-items: center;
	gap: 7px;
	font-size: 17px;
	font-weight: 700;
	letter-spacing: -.025em;
}

/* Monochrome. A wordmark that wears the pending lamp tells you something is
   pending every single time the app is open. */
.cr-brand span { color: var(--text); }

/* The mark: a leading chevron carrying a smaller one behind it. Inline so it
   costs no request and cannot 404 on a slow connection. */
.cr-logo { width: 21px; height: 21px; flex: none; display: block; color: var(--text); }

/*
 * The page title on the screens that have one — Activity and Account. Uber
 * leads both with a large left-aligned name and no card around it, which is
 * what makes a tab feel like a destination rather than another panel.
 */
.cr-page {
	font-size: 30px;
	font-weight: 700;
	letter-spacing: -.035em;
	line-height: 1.1;
	margin: 2px 0 16px;
}

.cr-out {
	background: none;
	border: 0;
	color: var(--text-2);
	font-size: 13.5px;
	cursor: pointer;
	padding: 6px 2px;
}
.cr-out:hover { color: var(--text); }

/* ------------------------------------------------------------------- cards */

.cr-card {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--r-card);
	padding: 16px 15px;
}

.cr-card + .cr-card { margin-top: 11px; }

/* Anything the person has to act on gets a stronger edge, so "this one
   matters" registers before any colour is processed. */
/* The card that carries the main action on a screen. A MODIFIER on .cr-card,
   nothing else — worn by the composer, the confirmed-ride banner, the alert and
   the results card, and it sets exactly one property on purpose.

   In 1.37.0 the compact button row on the meeting card was also called .cr-act,
   and a bare `.cr-act { display:flex; flex-direction:column; align-items:center;
   font-size:11px; padding:8px 2px }` therefore applied to all four of these
   cards as well. They became centred flex columns styled as though each were one
   small icon button: the composer's rows shrank to fit, its WHEN chips came out
   one pixel narrower than "Later today" needs, and the labels ellipsised. One
   line of CSS, four cards, every symptom on that screen.

   The buttons are .cr-way now. Do not name anything `.cr-act` again. */
.cr-card.cr-act { border-color: var(--line-strong); }

.cr-card.cr-quiet { background: transparent; }

.cr-card.cr-sunk {
	background: var(--sunken);
	border-color: transparent;
}

.cr h2 { font-size: 19px; margin: 0 0 6px; font-weight: 650; line-height: 1.25; }
.cr h3 { font-size: 15.5px; font-weight: 650; margin: 0 0 4px; }
.cr p  { margin: 0 0 14px; color: var(--text-2); font-size: 14px; }
.cr p.cr-tight { margin-bottom: 8px; }
.cr p b { color: var(--text); font-weight: 600; }

.cr-lab {
	display: block;
	font: 700 10px/1 var(--font-ui);
	letter-spacing: .13em;
	text-transform: uppercase;
	color: var(--text-3);
	margin-bottom: 7px;
}

/* ------------------------------------------------------------------- forms */

.cr label {
	display: block;
	font-size: 13px;
	font-weight: 600;
	margin: 14px 0 6px;
	color: var(--text);
}
.cr label .cr-opt { color: var(--text-2); font-weight: 400; }

.cr input[type=text],
.cr input[type=email],
.cr input[type=tel],
.cr input[type=number],
.cr input[type=time],
.cr select {
	width: 100%;
	/* 16px minimum, otherwise iOS Safari zooms the whole page on focus. */
	font-size: 16px;
	padding: 12px 13px;
	background: var(--sunken);
	border: 1px solid var(--line);
	border-radius: var(--r-ctl);
	color: var(--text);
	appearance: none;
}

/* White, not amber. A focused field is not a pending action, and on this ground
   white is the most visible ring there is. */
.cr input:focus,
.cr select:focus,
.cr textarea:focus {
	outline: none;
	border-color: var(--text);
	box-shadow: 0 0 0 3px rgba(0,0,0,.09);
}

.cr input::placeholder { color: var(--text-3); }

.cr textarea {
	width: 100%;
	font-size: 16px;
	font-family: inherit;
	padding: 12px 13px;
	background: var(--sunken);
	border: 1px solid var(--line);
	border-radius: var(--r-ctl);
	color: var(--text);
	resize: vertical;
}

.cr-code {
	letter-spacing: 10px;
	text-align: center;
	font-family: var(--font-data) !important;
	font-size: 26px !important;
	font-weight: 700;
	padding: 14px 13px !important;
}

/* ----------------------------------------------------------------- buttons */

.cr-btn {
	display: block;
	width: 100%;
	margin-top: 12px;
	padding: 14px 10px;
	font-size: 14.5px;
	font-weight: 650;
	letter-spacing: -.01em;
	border: 1px solid var(--line-strong);
	border-radius: var(--r-ctl);
	background: transparent;
	color: var(--text);
	cursor: pointer;
	min-height: 48px;
}

/* The one primary action on a screen. A white fill on ink is the loudest object
   in the system, and it appears at most once — which is the only reason it is
   loud. Amber used to do this job and also mean "live" and also be the brand. */
.cr-btn.cr-pri {
	background: var(--pri);
	border-color: var(--pri);
	color: var(--pri-ink);
	font-weight: 700;
}
.cr-btn.cr-pri:hover:not(:disabled) { background: var(--pri-hover); border-color: var(--pri-hover); }

/* Accepting something wears the colour of the state it produces. */
.cr-btn.cr-go {
	background: var(--go-solid);
	border-color: var(--go-solid);
	color: var(--go-ink);
}

/*
 * The same act, offered a second and third time down the list.
 *
 * Taking an advertised seat confirms on the spot, so it has to keep the green
 * — but four solid green buttons is four equal recommendations, which is no
 * recommendation and is how you tap the wrong stranger. The nearest one is
 * filled; the rest carry the colour without the weight.
 */
.cr-btn.cr-go-out {
	background: var(--go-tint);
	border-color: var(--go-edge);
	color: var(--go);
	font-weight: 700;
}

.cr-btn.cr-ghost {
	background: none;
	border: 1px solid var(--line);
	color: var(--text);
}

.cr-btn.cr-wk {
	border-style: dashed;
	border-color: var(--line);
	color: var(--text-2);
	font-weight: 500;
}

.cr-btn:disabled { opacity: .45; cursor: default; }

.cr-link {
	background: none;
	border: 0;
	color: var(--text);
	font-size: 13.5px;
	cursor: pointer;
	padding: 12px 0 2px;
	display: block;
	width: 100%;
	text-align: center;
}
.cr-link:disabled { color: var(--text-2); cursor: default; }

.cr-row { display: flex; gap: 9px; }
.cr-row > * { flex: 1; }
.cr-row .cr-btn { margin-top: 0; }

.cr-stack { display: flex; flex-direction: column; gap: 9px; }
.cr-stack .cr-btn { margin-top: 0; }

/* Everything below this line is comfortably inside a right thumb's arc. It is
   where the primary action lives on any screen tall enough to have a choice. */
.cr-foot { margin-top: 16px; }

.cr-choice { display: flex; gap: 7px; margin-top: 6px; }
.cr-choice label {
	flex: 1;
	margin: 0;
	text-align: center;
	padding: 12px 6px;
	border: 1px solid var(--line);
	border-radius: var(--r-ctl);
	cursor: pointer;
	font-weight: 500;
	background: var(--sunken);
	min-height: 46px;
	display: grid;
	place-items: center;
}
.cr-choice input { position: absolute; opacity: 0; pointer-events: none; }

/*
 * A picked option is a selection, not a pending action, so it does not get the
 * pending lamp — and it does not get the white fill either, because that is the
 * primary button's and there is one of those per screen. A white edge and a
 * lifted surface says "this one" without shouting over the button below it.
 */
.cr-choice input:checked + span { color: var(--text); font-weight: 700; }
.cr-choice label:has(input:checked) {
	border-color: var(--text);
	background: var(--surface);
	box-shadow: inset 0 0 0 1px var(--text);
}
.cr-choice label:has(input:disabled) { opacity: .4; cursor: default; }

/*
 * `.cr label` is 0-1-1 and `.cr-check` is 0-1-0, so the generic display:block
 * quietly beat this and the tick sat on its own line above its own words. It
 * needs the type selector to win its own rule back.
 */
.cr label.cr-check,
.cr-check {
	display: flex;
	gap: 11px;
	align-items: flex-start;
	margin: 14px 0 0;
	padding: 13px;
	border: 1px solid var(--line);
	border-radius: var(--r-ctl);
	background: var(--sunken);
	cursor: pointer;
}

/* accent-color only paints the checked state; unchecked stays the platform
   default, which is a stark white square on a near-black card. Draw the whole
   control instead so both states belong to the palette. */
.cr-check input[type=checkbox] {
	appearance: none;
	-webkit-appearance: none;
	width: 20px;
	height: 20px;
	margin: 1px 0 0;
	flex: none;
	border: 1px solid var(--line-strong);
	border-radius: 5px;
	background: var(--bg);
	cursor: pointer;
	display: grid;
	place-items: center;
}
.cr-check input[type=checkbox]:checked {
	background: var(--pri);
	border-color: var(--pri);
}
.cr-check input[type=checkbox]:checked::after {
	content: '';
	width: 5px;
	height: 9px;
	border: solid var(--pri-ink);
	border-width: 0 2px 2px 0;
	transform: rotate(45deg) translate(-1px, -1px);
}
.cr-check b { display: block; font-size: 14px; font-weight: 600; }
.cr-check small { color: var(--text-2); font-size: 12.5px; line-height: 1.45; display: block; margin-top: 2px; }

.cr-fold { display: none; }
.cr-fold.cr-open { display: block; }

/* --------------------------------------------------------------- messaging */

.cr-msg {
	margin-top: 12px;
	padding: 11px 13px;
	border-radius: var(--r-ctl);
	font-size: 13.5px;
	display: none;
}
.cr-msg.cr-show { display: block; }
.cr-msg.cr-bad  { background: var(--alert-tint); color: var(--alert); border: 1px solid var(--alert-edge); }
.cr-msg.cr-good { background: var(--go-tint);    color: var(--go);    border: 1px solid var(--go-edge); }

.cr-note {
	margin-top: 12px;
	padding: 11px 13px;
	background: var(--sunken);
	border-radius: var(--r-ctl);
	color: var(--text-2);
	font-size: 13px;
	line-height: 1.55;
}
.cr-note b { color: var(--text); font-weight: 600; }

/* ------------------------------------------------------------------- chips */

.cr-pill {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	font: 700 10.5px/1.35 var(--font-ui);
	letter-spacing: .07em;
	text-transform: uppercase;
	padding: 4px 10px;
	border-radius: 999px;
	border: 1px solid var(--line-strong);
	color: var(--text-2);
	background: transparent;
	vertical-align: middle;
}

/* A job for the person reading it. The only solid fill among the chips, and
   never more than one on a screen. */
.cr-pill.cr-ask {
	background: var(--signal-solid);
	border-color: var(--signal-solid);
	color: var(--signal-ink);
}

/* Live right now, and will expire on its own. Tint, not fill: it is happening
   but it is not your job. */
.cr-pill.cr-live {
	background: var(--signal-tint);
	border-color: var(--signal-edge);
	color: var(--signal);
}

.cr-pill.cr-ok {
	background: var(--go-tint);
	border-color: var(--go-edge);
	color: var(--go);
}

/* The one blue thing in the app: a human checked this person's ID. */
.cr-pill.cr-trust {
	background: var(--trust-tint);
	border-color: var(--trust-edge);
	color: var(--trust);
}

.cr-pill.cr-wait { background: transparent; border-color: var(--line-strong); color: var(--text-2); }
.cr-pill.cr-free { background: var(--go-tint); border-color: var(--go-edge); color: var(--go); }

/* Money keeps its own case and its own face. The taka sign is U+09F3, which
   the uppercase transform and the UI stack between them render as something
   close to a colon on desktop — and a price nobody can read is worse than no
   pill at all. The data face has it, and tabular figures line the amounts up. */
.cr-pill.cr-money {
	text-transform: none;
	letter-spacing: 0;
	font-family: var(--font-data);
	font-variant-numeric: tabular-nums;
	font-size: 11px;
}

.cr-pills { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }

/* Slow, one per screen, and gone entirely for anyone who has asked for less
   motion. It exists to prove the app is still awake, not to demand attention. */
.cr-dot {
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--signal);
	flex: none;
	animation: cr-blink 2.4s ease-in-out infinite;
}
@keyframes cr-blink { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

@media ( prefers-reduced-motion: reduce ) {
	.cr-dot { animation: none; }
	.cr * { transition: none !important; }
}

.cr-asking { color: var(--signal) !important; font-weight: 600; }

.cr-badge {
	display: inline-block;
	min-width: 20px;
	padding: 2px 7px;
	margin-left: 6px;
	border-radius: 999px;
	background: var(--signal-solid);
	color: var(--signal-ink);
	font: 700 11.5px/1.4 var(--font-data);
	vertical-align: middle;
}

/* ------------------------------------------------------------------ icons */

/*
 * One family: 24-unit grid, one 2px stroke, round everything. Sized in em so a
 * glyph is always in proportion to the words beside it, and coloured by
 * currentColor so it can never disagree with its own label.
 */
.cr-ico {
	width: 1.15em;
	height: 1.15em;
	flex: none;
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
	vertical-align: -.18em;
}

.cr-ico-lg { width: 1.6em; height: 1.6em; }
.cr-ico-xl { width: 26px; height: 26px; stroke-width: 1.8; }

/* Pills and tags carry their icon a touch smaller — at pill size a 1.15em
   glyph out-shouts the word it belongs to. */
.cr-pill .cr-ico,
.cr-tag .cr-ico { width: 1.05em; height: 1.05em; stroke-width: 2.2; }

/* ------------------------------------------------------- the route visual */

/*
 * The two-point metaphor every transport app trains people on: where you get
 * on, where you get off, and a line between them. It is a diagram, not a map —
 * it never claims to show the actual road, which is what screenRoute is for.
 */
.cr-trip-viz { display: flex; gap: 11px; align-items: stretch; }

.cr-viz-rail {
	position: relative;
	width: 12px;
	flex: none;
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: 4px 0 2px;
}

/* Origin: a plain ring. You are already there, so it needs no emphasis. */
.cr-viz-rail::before {
	content: '';
	width: 10px;
	height: 10px;
	border-radius: 50%;
	border: 2px solid var(--text-2);
	flex: none;
}

/* Destination: a filled square. Ring for where you are, square for where you
   are going, is the pairing every trip planner has trained people on — and it
   frees the pending lamp from a job it was doing for decoration. */
.cr-viz-rail::after {
	content: '';
	width: 10px;
	height: 10px;
	flex: none;
	border-radius: 2px;
	background: var(--text);
}

.cr-viz-line {
	flex: 1 1 auto;
	width: 0;
	min-height: 16px;
	margin: 3px 0;
	border-left: 2px dashed var(--line-strong);
}

.cr-viz-txt {
	flex: 1 1 auto;
	min-width: 0;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: 8px;
}
.cr-viz-txt b {
	display: block;
	font-size: 14.5px;
	font-weight: 650;
	letter-spacing: -.01em;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.cr-viz-txt small { display: block; color: var(--text-2); font-size: 12px; margin-top: 1px; }

/* Compact variant for list rows, where the whole card is only two lines tall. */
.cr-trip-viz.cr-viz-sm .cr-viz-line { min-height: 10px; }
.cr-trip-viz.cr-viz-sm .cr-viz-txt b { font-size: 14px; }

/* --------------------------------------------------------- the ride card */

/*
 * One shape for "a ride", wherever a ride appears. Before this, the same idea
 * was a list row on one screen, a bordered card on another and a bare heading
 * on a third, so nothing in the app looked like it belonged to the same
 * product. The meta strip along the bottom is the ride-hailing readout: walk,
 * time, price, all in the data face.
 */
.cr-meta {
	display: flex;
	flex-wrap: wrap;
	gap: 6px 14px;
	margin-top: 11px;
	padding-top: 10px;
	border-top: 1px solid var(--line);
	font-size: 12.5px;
	color: var(--text-2);
}
.cr-meta span { display: inline-flex; align-items: center; gap: 5px; }
.cr-meta b {
	color: var(--text);
	font-weight: 650;
	font-family: var(--font-data);
	font-variant-numeric: tabular-nums;
}
.cr-meta .cr-free-txt { color: var(--go); font-weight: 650; }

/* ------------------------------------------------- the vehicle identity */

/*
 * The one physical thing a student has to recognise in the dark, at a kerb,
 * with thirty seconds to decide whether to get on. It was a sentence inside a
 * note; a car's colour and plate get a card of their own in every ride-hailing
 * app, and a bike is no different.
 */
.cr-vehicle {
	display: flex;
	align-items: center;
	gap: 13px;
	margin-top: 11px;
	padding: 13px;
	border: 1px solid var(--line-strong);
	border-radius: var(--r-card);
	background: var(--sunken);
}
.cr-vehicle .cr-ico { width: 30px; height: 30px; stroke-width: 1.7; color: var(--text-2); }
.cr-vehicle .cr-v-txt { min-width: 0; flex: 1 1 auto; }
.cr-vehicle .cr-plate {
	margin: 0 0 2px;
	font-size: 16px;
	letter-spacing: .04em;
	word-break: break-word;
}
.cr-vehicle small { display: block; color: var(--text-2); font-size: 12.5px; line-height: 1.45; }

/* --------------------------------------------------------- more/less tags */

.cr-more {
	background: none;
	border: 1px dashed var(--line-strong);
	color: var(--text-2);
	border-radius: 999px;
	padding: 4px 11px;
	font: 700 10.5px/1.35 var(--font-ui);
	letter-spacing: .07em;
	text-transform: uppercase;
	cursor: pointer;
}
.cr-more:hover { color: var(--text); }
.cr-tags .cr-tag[hidden] { display: none; }

/* ----------------------------------------------------------------- stepper */

/* Where you are in a booking, readable without reading. Green behind for what
   is done, amber for where you are, grey ahead. */
.cr-step { display: flex; gap: 4px; margin: 4px 0 0; }
.cr-step i { flex: 1; height: 4px; border-radius: 2px; background: var(--line); }
.cr-step i.cr-on  { background: var(--go-solid); }
.cr-step i.cr-now { background: var(--signal-solid); }

.cr-steplab {
	display: flex;
	justify-content: space-between;
	margin-top: 6px;
	font: 600 9px/1 var(--font-ui);
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--text-3);
}

/* --------------------------------------------------------- facts and lists */

.cr-facts { list-style: none; margin: 0; padding: 0; }
.cr-facts li {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 14px;
	padding: 11px 0;
	border-bottom: 1px solid var(--line);
	font-size: 13.5px;
}
.cr-facts li:last-child { border-bottom: 0; }
.cr-facts span { color: var(--text-2); }
.cr-facts b { font-weight: 600; text-align: right; font-size: 13.5px; }

.cr-list { list-style: none; margin: 4px 0 0; padding: 0; }
.cr-list li {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 12px 0;
	border-bottom: 1px solid var(--line);
}
.cr-list li:last-child { border-bottom: 0; }
.cr-list b { font-weight: 600; font-size: 14.5px; }
.cr-list small { display: block; color: var(--text-2); font-size: 12.5px; margin-top: 3px; }

.cr-row-acts { display: flex; gap: 6px; flex: none; flex-wrap: wrap; }

/* A saved place leads with the same glyph the trip picker uses for one, so the
   two lists teach each other rather than looking like unrelated screens. */
.cr-rowmain { display: flex; align-items: center; gap: 12px; flex: 1 1 auto; min-width: 0; }
.cr-rowmain .cr-rowico { width: 19px; height: 19px; color: var(--text-2); flex: none; }

/*
 * A place row carries two buttons and sits happily beside its text. A route row
 * carries five - Leaving now, Find rides, Route, Edit, Delete - which is far
 * more than fits next to a description on a phone, so they shoved the text into
 * a two-character column and the row fell apart. Routes get their own shape:
 * description on its own line, actions wrapping underneath.
 */
.cr-list li.cr-trip-row {
	display: block;
	padding: 14px 0;
}

.cr-trip-row > div:first-child { margin-bottom: 10px; }

.cr-trip-row .cr-row-acts {
	gap: 7px;
	width: 100%;
}

/* Finger-sized, and never narrower than the word inside them. */
.cr-trip-row .cr-mini {
	min-height: 38px;
	white-space: nowrap;
}

@media ( max-width: 420px ) {
	/*
	 * Tighter, but never stretched to fill the row. Letting them flex-grow put
	 * Delete alone on the last line at full width, which made the one
	 * destructive button the largest target on the screen.
	 */
	.cr-trip-row .cr-mini { padding: 8px 9px; font-size: 12.5px; }
	.cr-list li { flex-wrap: wrap; }
	.cr-list li > .cr-row-acts { margin-left: auto; }
}

.cr-mini {
	background: none;
	border: 1px solid var(--line);
	color: var(--text-2);
	border-radius: var(--r-sm);
	padding: 7px 10px;
	font-size: 12.5px;
	font-weight: 600;
	cursor: pointer;
}
.cr-mini:hover { color: var(--text); border-color: var(--line-strong); }

/* Destructive controls are neutral until the confirming tap. Red on screen
   always means you are one tap from doing it. */
.cr-mini.cr-danger:hover { color: var(--alert); border-color: var(--alert); }
.cr-mini[data-state=sure] { color: var(--alert); border-color: var(--alert); background: var(--alert-tint); }
.cr-btn[data-state=sure]  { color: var(--alert); border-color: var(--alert); background: var(--alert-tint); }

/* "Leaving now" is an action, not a pending state — neutral, like every other
   row button. Only what is genuinely waiting on the person wears amber. */
.cr-mini.cr-now { border-color: var(--line-strong); color: var(--text); }
.cr-mini.cr-go  { border-color: var(--line-strong); color: var(--text); }

.cr-empty {
	color: var(--text-2);
	font-size: 13.5px;
	padding: 14px;
	border: 1px dashed var(--line);
	border-radius: var(--r-ctl);
	margin: 4px 0 0;
	line-height: 1.55;
}

.cr-divide {
	display: flex;
	align-items: center;
	gap: 9px;
	margin: 18px 0 8px;
	font: 700 10px/1 var(--font-ui);
	letter-spacing: .13em;
	text-transform: uppercase;
	color: var(--text-3);
}
.cr-divide::after { content: ''; flex: 1; height: 1px; background: var(--line); }

/* ------------------------------------------------------- the person's card */

.cr-match {
	border: 1px solid var(--line);
	border-radius: var(--r-card);
	padding: 15px 14px;
	margin-bottom: 11px;
	background: var(--surface);
}

/* The recommended one. Three identical primaries is three equal choices and no
   recommendation; one default and the rest alternatives is a decision. */
.cr-match.cr-lead { border-color: var(--line-strong); }

.cr-match-top { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start; }
.cr-match-top b { font-size: 16px; font-weight: 650; letter-spacing: -.02em; }
.cr-match-top small { display: block; color: var(--text-2); font-size: 12.5px; margin-top: 3px; }

/*
 * Karma carries no colour at all, on purpose. A number that looks like a
 * measurement gets believed; a number wearing a status colour reads as a badge
 * the app is awarding — and the app cannot vouch for a stranger.
 */
.cr-karma { text-align: center; flex: none; padding-left: 6px; }
.cr-karma b { display: block; font-size: 21px; font-weight: 700; color: var(--text); line-height: 1; }
.cr-karma small {
	display: block;
	margin-top: 4px;
	color: var(--text-3);
	font: 600 9px/1 var(--font-ui);
	text-transform: uppercase;
	letter-spacing: .11em;
}
.cr-karma.cr-new b { color: var(--text-3); font-size: 17px; }

.cr-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 10px; }
.cr-tag {
	font: 700 10.5px/1.35 var(--font-ui);
	letter-spacing: .07em;
	text-transform: uppercase;
	padding: 4px 10px;
	border-radius: 999px;
	border: 1px solid var(--line-strong);
	color: var(--text-2);
}

.cr-walk {
	display: flex;
	justify-content: space-between;
	gap: 10px;
	margin-top: 11px;
	padding: 10px 12px;
	background: var(--sunken);
	border-radius: var(--r-ctl);
	font-size: 12.5px;
	color: var(--text-2);
}
.cr-walk b { color: var(--text); font-weight: 650; font-family: var(--font-data); font-variant-numeric: tabular-nums; }

.cr-match .cr-btn { margin-top: 12px; }

/*
 * Somebody already on the road, as opposed to somebody whose saved week says
 * they usually are. It is the one distinction this screen exists to make, so
 * it gets the live colour and a left edge — amber is "happening now" here as
 * it is everywhere else, and it is deliberately NOT green: nothing has been
 * agreed yet, and green in this app means confirmed.
 */
.cr-match.cr-onroad {
	border-color: var(--signal-edge);
	box-shadow: inset 3px 0 0 var(--signal-solid);
}

/* Somebody who was not there a moment ago.
 *
 * The whole promise of a live search is that the board keeps answering for the
 * length of the timer, which means rows appear under somebody who is already
 * reading. A row that arrives silently and identically is a row that is missed,
 * so it arrives lit and settles into the list over three seconds — long enough
 * to catch an eye that was elsewhere, short enough that it is not still glowing
 * when the thumb gets there. */
.cr-match.cr-arrived {
	animation: cr-arrive 3s ease-out 1;
}
@keyframes cr-arrive {
	0%   { box-shadow: 0 0 0 2px var(--go-solid); transform: translateY(-4px); opacity: .35; }
	12%  { transform: translateY(0); opacity: 1; }
	70%  { box-shadow: 0 0 0 2px var(--go-solid); }
	100% { box-shadow: 0 0 0 2px transparent; }
}
@media (prefers-reduced-motion: reduce) {
	.cr-match.cr-arrived { animation: none; border-color: var(--go-edge); }
}

.cr-found {
	color: var(--text-3);
	font: 700 10px/1 var(--font-ui);
	letter-spacing: .13em;
	text-transform: uppercase;
	margin: 16px 0 9px;
}

/* Where the seats that can be taken stop and the ones that have to be asked
   for begin. Drawn once, as a rule across the list, because the difference is
   a boundary rather than a property of each row. */
.cr-rule {
	display: flex;
	align-items: center;
	gap: 10px;
	margin: 18px 0 10px;
	color: var(--text-3);
	font: 700 10px/1 var(--font-ui);
	letter-spacing: .13em;
	text-transform: uppercase;
}
.cr-rule::before,
.cr-rule::after { content: ''; flex: 1; height: 1px; background: var(--line); }

/* The sentence under a button that says what pressing it will actually cost —
   an answer straight away, or a wait on somebody else. Quiet on purpose: it
   explains the button without competing with it. */
.cr-fine {
	color: var(--text-3);
	font-size: 12px;
	margin: 7px 0 0;
	text-align: center;
}

/* --------------------------------------------------------- state surfaces */

/* Something is waiting on you. The ride does not happen until this is
   answered, and it used to be invisible from the home screen. */
.cr-alert {
	border-color: var(--signal-edge);
	background: linear-gradient( 180deg, var(--signal-tint), var(--surface) 70% );
}
.cr-alert h2 { color: var(--text); }

.cr-alert.cr-alert-ok {
	border-color: var(--go-edge);
	background: linear-gradient( 180deg, var(--go-tint), var(--surface) 70% );
}

.cr-onboard { border-color: var(--signal-edge); }

/* The go-live screen is the only one tinted end to end. It is the
   high-urgency path and should feel unlike scheduling something for Tuesday. */
.cr-hot {
	border-color: var(--signal-edge);
	background: linear-gradient( 180deg, var(--signal-tint), var(--surface) 60% );
}

/* The code said out loud at the kerb. Green because it is the proof the
   confirmation was real, and big because it is read at arm's length in the
   dark, which is the only situation it is ever used in. */
.cr-pin {
	margin-top: 12px;
	padding: 16px 12px;
	border: 1px solid var(--go-edge);
	border-radius: var(--r-card);
	background: var(--surface);
	text-align: center;
}
.cr-pin b {
	display: block;
	font-size: 42px;
	font-weight: 800;
	letter-spacing: .16em;
	line-height: 1.1;
	color: var(--go);
	/* The last digit's letter-spacing would otherwise push it off centre. */
	text-indent: .16em;
}
.cr-pin small {
	display: block;
	margin-top: 8px;
	color: var(--text-2);
	font-size: 12.5px;
	line-height: 1.5;
}

.cr-plate {
	display: block;
	font-size: 15px;
	font-weight: 700;
	letter-spacing: .03em;
	color: var(--text);
	margin: 2px 0 4px;
}

/* ------------------------------------------------------ the live search */

/*
 * The countdown, and under it the running account of what is actually being
 * done. A conic gradient rather than an animated SVG: it is one repaint a
 * second on a phone that may be three years old, and it degrades to a plain
 * ring on anything that cannot draw it.
 */
.cr-timer {
	position: relative;
	width: 132px;
	height: 132px;
	margin: 18px auto 4px;
	display: grid;
	place-items: center;
}
.cr-timer i {
	position: absolute;
	inset: 0;
	border-radius: 50%;
	background: conic-gradient( var(--signal-solid) var(--at, 0%), var(--line) 0 );
	-webkit-mask: radial-gradient( farthest-side, transparent calc(100% - 7px), #000 calc(100% - 6px) );
	mask: radial-gradient( farthest-side, transparent calc(100% - 7px), #000 calc(100% - 6px) );
	transition: background .9s linear;
}
.cr-timer b {
	font: 700 34px/1 var(--font-data);
	font-variant-numeric: tabular-nums;
	letter-spacing: -.03em;
	color: var(--text);
}

/* The clock stops mattering the moment the search is over. */
.cr-timer.cr-timer-done i { background: var(--line); }
.cr-timer.cr-timer-done b { color: var(--text-3); }

@media ( prefers-reduced-motion: reduce ) {
	.cr-timer i { transition: none; }
}

/*
 * One line per thing that happened, oldest at the top. Capped in height so a
 * long search cannot push the Stop button off the screen — the one control
 * that must never become unreachable.
 */
.cr-log {
	list-style: none;
	margin: 14px 0 0;
	padding: 0;
	max-height: 170px;
	overflow-y: auto;
	font-size: 13.5px;
	color: var(--text-2);
}
.cr-log li {
	display: flex;
	align-items: baseline;
	gap: 9px;
	padding: 6px 0;
	animation: cr-line .35s ease both;
}
.cr-log li::before {
	content: '';
	width: 5px;
	height: 5px;
	flex: none;
	border-radius: 50%;
	background: var(--line-strong);
	transform: translateY(-2px);
}

/* The last line is where the eye should be. */
.cr-log li:last-child { color: var(--text); font-weight: 600; }
.cr-log li:last-child::before { background: var(--signal-solid); }

.cr-log li.cr-good { color: var(--go); font-weight: 600; }
.cr-log li.cr-good::before { background: var(--go-solid); }

@keyframes cr-line {
	from { opacity: 0; transform: translateY(4px); }
	to   { opacity: 1; transform: none; }
}

@media ( prefers-reduced-motion: reduce ) {
	.cr-log li { animation: none; }
}

/* Proof the app is still awake while nothing is happening. */
.cr-heartbeat {
	display: flex;
	align-items: center;
	gap: 7px;
	margin-top: 10px;
	font-size: 11.5px;
	color: var(--text-3);
}

.cr-bar { height: 5px; border-radius: 3px; background: var(--line); overflow: hidden; margin-top: 10px; }
.cr-bar i { display: block; height: 100%; background: var(--text); border-radius: 3px; transition: width .6s ease; }

.cr-contact { display: flex; gap: 8px; margin-top: 12px; }
.cr-contact a {
	flex: 1;
	text-align: center;
	padding: 13px 8px;
	border-radius: var(--r-ctl);
	font-size: 14px;
	font-weight: 650;
	text-decoration: none;
	border: 1px solid var(--line-strong);
	color: var(--text);
	min-height: 48px;
	display: grid;
	place-items: center;
}
/* Confirmed channel, and the green Bangladesh already reads as WhatsApp. */
.cr-contact a.cr-wa { background: var(--go-solid); color: var(--go-ink); border-color: var(--go-solid); }

.cr-row-links {
	display: flex;
	justify-content: space-between;
	gap: 12px;
	margin-top: 6px;
	padding-top: 8px;
	border-top: 1px dashed var(--line);
}
/* 26px tall before this, which is under a fingertip on a phone being held one
   handed - and one of the two is "Report or block". The type stays small; only
   the thing being aimed at grows. */
.cr-row-links .cr-link {
	width: auto;
	text-align: left;
	font-size: 12.5px;
	color: var(--text-2);
	padding: 13px 0 9px;
	min-height: 44px;
	display: inline-flex;
	align-items: center;
}
.cr-row-links .cr-link:hover { color: var(--text); }
.cr-row-links .cr-link[data-report]:hover { color: var(--alert); }

/* ---------------------------------------------------------- live capture */

.cr-steps { list-style: none; counter-reset: s; margin: 14px 0 0; padding: 0; }
.cr-steps li {
	counter-increment: s;
	position: relative;
	padding: 0 0 14px 38px;
	font-size: 14px;
}
.cr-steps li::before {
	content: counter(s);
	position: absolute;
	left: 0;
	top: 0;
	width: 26px;
	height: 26px;
	border-radius: 50%;
	background: var(--sunken);
	border: 1px solid var(--line-strong);
	color: var(--text);
	font: 700 13px/1 var(--font-data);
	display: grid;
	place-items: center;
}
.cr-steps b { display: block; font-weight: 650; }
.cr-steps span { color: var(--text-2); font-size: 13px; }

.cr-stage {
	position: relative;
	margin-top: 12px;
	border-radius: var(--r-card);
	overflow: hidden;
	background: #000;
	border: 1px solid var(--line);
}

.cr-stage video {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* Deliberately not mirrored: a mirrored preview makes people flip the ID
	   card round, and then the writing is backwards in the photo. */
}

.cr-card-stage   { aspect-ratio: 4 / 3; }
.cr-selfie-stage { aspect-ratio: 3 / 4; }

/* Fallback for browsers without aspect-ratio. */
@supports not ( aspect-ratio: 1 ) {
	.cr-card-stage   { height: 260px; }
	.cr-selfie-stage { height: 420px; }
}

/* Bracketed corners rather than a full dashed box — the convention every ID
   capture flow uses, and it leaves the card itself unobstructed. */
.cr-guide {
	position: absolute;
	inset: 11% 7%;
	pointer-events: none;
	/* Hard white, not the theme's ink. These sit on a live camera feed, not on
	   the page, and the primary colour going black would lose them against a
	   dark room every time. */
	background:
		linear-gradient(#fff,#fff) left  top    / 26px 3px no-repeat,
		linear-gradient(#fff,#fff) left  top    / 3px 26px no-repeat,
		linear-gradient(#fff,#fff) right top    / 26px 3px no-repeat,
		linear-gradient(#fff,#fff) right top    / 3px 26px no-repeat,
		linear-gradient(#fff,#fff) left  bottom / 26px 3px no-repeat,
		linear-gradient(#fff,#fff) left  bottom / 3px 26px no-repeat,
		linear-gradient(#fff,#fff) right bottom / 26px 3px no-repeat,
		linear-gradient(#fff,#fff) right bottom / 3px 26px no-repeat;
}

.cr-prompt {
	position: absolute;
	left: 0; right: 0; bottom: 0;
	padding: 14px 16px;
	background: linear-gradient( to top, rgba(0,0,0,.88), rgba(0,0,0,0) );
	color: #fff;
	font-size: 15px;
	font-weight: 650;
	text-align: center;
}

.cr-count {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
	font-family: var(--font-data);
	font-size: 88px;
	font-weight: 800;
	color: #fff;
	text-shadow: 0 3px 22px rgba(0,0,0,.85);
	pointer-events: none;
}

.cr-shot {
	margin-top: 12px;
	border-radius: var(--r-card);
	overflow: hidden;
	background: #000;
	border: 1px solid var(--line);
}
.cr-shot img { display: block; width: 100%; height: auto; }

/* --------------------------------------------------------- place search */

.cr-search { position: relative; margin-top: 12px; z-index: 5; }

/* Same shape as the search pill on the home screen, so "type a place" looks
   like one thing wherever the app asks for it. */
.cr-search input[type=search] {
	width: 100%;
	font-size: 16px;
	padding: 14px 16px;
	background: var(--sunken);
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	color: var(--text);
	appearance: none;
}
.cr-search input:focus { outline: none; border-color: var(--text); box-shadow: 0 0 0 3px rgba(0,0,0,.09); }

.cr-hits {
	display: none;
	position: absolute;
	left: 0;
	right: 0;
	top: calc(100% + 4px);
	margin: 0;
	padding: 4px;
	list-style: none;
	background: var(--surface);
	border: 1px solid var(--line-strong);
	border-radius: var(--r-ctl);
	box-shadow: 0 14px 34px rgba(0,0,0,.16);
	max-height: 260px;
	overflow-y: auto;
}
.cr-hits.cr-open { display: block; }

.cr-hits li {
	padding: 11px;
	border-radius: var(--r-sm);
	cursor: pointer;
}
.cr-hits li:hover { background: var(--sunken); }
.cr-hits b { display: block; font-size: 14px; font-weight: 600; }
.cr-hits small {
	display: block;
	color: var(--text-2);
	font-size: 12.5px;
	margin-top: 1px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.cr-hits li.cr-none { color: var(--text-2); font-size: 13px; cursor: default; }
.cr-hits li.cr-none:hover { background: none; }

/* -------------------------------------------------------------------- map */

.cr-mapwrap { margin-top: 12px; }

.cr-map {
	position: relative;
	height: 300px;
	border-radius: var(--r-card);
	overflow: hidden;
	border: 1px solid var(--line);
	background: var(--sunken);
	cursor: grab;
	/* The page keeps vertical scrolling. A map embedded in a scrolling screen
	   that declares touch-action: none swallows every thumb that lands on it,
	   and on the meeting screen that is a 260 px trap across the middle of the
	   page. Two fingers move the map; see CRMap.own. */
	touch-action: pan-y;
	user-select: none;
}
/* Where the map IS the task — placing a pin — it takes the whole gesture. */
.cr-map.cr-map-own { touch-action: none; }
.cr-map:active { cursor: grabbing; }
.cr-map:focus-visible { outline: 2px solid var(--pri); outline-offset: 2px; }

/* Said only to somebody who has just tried to move the map the other way. */
.cr-map-hint {
	position: absolute;
	left: 50%;
	bottom: 14px;
	transform: translateX(-50%);
	z-index: 5;
	padding: 7px 13px;
	border-radius: 999px;
	background: rgba(17,20,24,.82);
	color: #fff;
	font-size: 12.5px;
	font-weight: 600;
	white-space: nowrap;
	pointer-events: none;
	opacity: 0;
	transition: opacity .2s ease;
}
.cr-map-hint.cr-on { opacity: 1; }

.cr-map-plane { position: absolute; inset: 0; }

/* The route line. Casing under core so it reads on pale streets and on
   satellite imagery without needing a different colour for each. The core is
   a violet that appears in none of the four tile styles, so the corridor is
   never lost in a road — and it stays outside the semantic palette, so the map
   never looks like it is offering an action. */
.cr-map-line {
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
	overflow: visible;
	pointer-events: none;
}
.cr-line-case {
	stroke: rgba(0,0,0,.6);
	stroke-width: 10;
	stroke-linecap: round;
	stroke-linejoin: round;
}
.cr-line-core {
	stroke: var(--route);
	stroke-width: 5;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* WHICH WAY HE IS COMING DOWN IT. A road drawn as a line has two ends, and on
   a still map you work out which end he is coming from by looking at where the
   dot is — and get it wrong. Chevrons say it without a word. */
.cr-line-way {
	stroke: #fff;
	stroke-width: 2.2;
	stroke-linecap: round;
	stroke-linejoin: round;
	opacity: .9;
}

/* WHERE HE GOES ON ALONE. The same road, drawn quieter, past the point she
   gets off it — thinner than the shared stretch and half its opacity, so it
   reads as the rest of one journey rather than as a second route. Only ever on
   the rider's phone, and the server trims its far end short of his door. */
.cr-map-tail {
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
	overflow: visible;
	pointer-events: none;
	opacity: .5;
}
.cr-tail-case {
	stroke: rgba(0,0,0,.45);
	stroke-width: 7.5;
	stroke-linecap: round;
	stroke-linejoin: round;
}
.cr-tail-core {
	stroke: var(--route);
	stroke-width: 3.5;
	stroke-dasharray: 9 7;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* THE WALK — the pavements, not the bearing.
 *
 * Deliberately not the route's colour: his line is a road a bike is coming
 * down, hers is the way she has to walk, and one must not be mistaken for the
 * other. Solid, where the bearing line is dashed, because this one IS the way
 * rather than the direction of it. */
.cr-map-walk {
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
	overflow: visible;
	pointer-events: none;
}
.cr-walk-case {
	stroke: rgba(0,0,0,.5);
	stroke-width: 9;
	stroke-linecap: round;
	stroke-linejoin: round;
}
.cr-walk-core {
	stroke: var(--go-solid);
	stroke-width: 4.5;
	stroke-linecap: round;
	stroke-linejoin: round;
}
.cr-walk-head {
	fill: var(--go-solid);
	stroke: rgba(0,0,0,.5);
	stroke-width: 2;
	stroke-linejoin: round;
}

/* How far across the screen actually is. Without it, "300 m away" is a number
   with nothing on the map to measure itself against — and the judgement this
   screen exists for is a judgement about distance. */
.cr-map-scale {
	position: absolute;
	left: 10px;
	bottom: 10px;
	z-index: 4;
	pointer-events: none;
	display: flex;
	align-items: center;
	gap: 6px;
}
.cr-map-scale i {
	display: block;
	height: 7px;
	border: 1.5px solid rgba(20,24,28,.7);
	border-top: 0;
	background: rgba(255,255,255,.4);
}
.cr-map-scale b {
	font: 700 10.5px/1 var(--font-ui);
	color: #1b1f24;
	text-shadow: 0 1px 2px rgba(255,255,255,.9);
}
/* WHICH WAY TO WALK. The route line says where the road goes; this says which
   end of it the other person is at, and it is the only thing on the map that
   moves along its own length — the marching dashes give it a direction before
   the arrowhead is even resolved, which at arm's length in daylight is what
   actually gets read. Drawn over the route and under the people. */
.cr-map-link {
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
	overflow: visible;
	pointer-events: none;
	z-index: 2;
}
/*
 * THE ORDER THINGS ARE PAINTED IN, stated once and in one place.
 *
 * Tiles carry a z-index of their own so a half-loaded new level can sit over
 * the old one, and that put them level with the route — which meant a tile
 * created after the line was drawn painted straight over the road. Equal
 * z-index is decided by DOM order, and tiles are created constantly.
 *
 *   0  the level below, held while this one loads
 *   1  the tiles
 *   2  his road, and under it the part of it she is not on
 *   3  her walk
 *   4  the bearing arrow
 *   5  the people
 */
.cr-map-tail  { z-index: 2; }
.cr-map-line  { z-index: 2; }
.cr-map-walk  { z-index: 3; }
.cr-map-link  { z-index: 4; }
.cr-map-marks { z-index: 5; }

.cr-link-case {
	stroke: rgba(0,0,0,.55);
	stroke-width: 8;
	stroke-linecap: round;
}
.cr-link-core {
	stroke: var(--go-solid);
	stroke-width: 3.5;
	stroke-linecap: round;
	stroke-dasharray: 9 7;
	animation: cr-march 1s linear infinite;
}
.cr-link-head {
	fill: var(--go-solid);
	stroke: rgba(0,0,0,.55);
	stroke-width: 2;
	stroke-linejoin: round;
}
@keyframes cr-march {
	to { stroke-dashoffset: -16; }
}
@media (prefers-reduced-motion: reduce) {
	.cr-link-core { animation: none; }
}

/* Positioned by transform, so left/top stay at the origin and the browser
   never lays the page out to move one. Faded in because a tile that appears
   instantly at full strength pops, and a whole grid of them popping in a
   random order is the thing that makes a home-made map look home-made. */
.cr-tile {
	position: absolute;
	left: 0;
	top: 0;
	width: 256px;
	height: 256px;
	pointer-events: none;
	opacity: 0;
	transition: opacity .18s linear;
	/* The backdrop level is drawn scaled up from this corner, so the corner is
	   where the scaling has to happen from. */
	transform-origin: 0 0;
}
.cr-tile.cr-tile-on { opacity: 1; }

/* Asked for three times and never arrived. A plain surface reads as "no detail
   here"; the browser's broken-image mark reads as a broken app. */
.cr-tile.cr-tile-gone {
	opacity: 1;
	background: var(--sunken);
}

@media (prefers-reduced-motion: reduce) {
	.cr-tile { transition: none; }
}

/* The pin is fixed dead centre; the map moves under it. */
.cr-map-pin {
	position: absolute;
	left: 50%;
	top: 50%;
	width: 0;
	height: 0;
	pointer-events: none;
}
.cr-map-pin span {
	position: absolute;
	left: -11px;
	top: -26px;
	width: 22px;
	height: 22px;
	border-radius: 50% 50% 50% 0;
	transform: rotate(-45deg);
	background: var(--pri);
	border: 2px solid var(--bg);
	box-shadow: 0 3px 10px rgba(0,0,0,.7);
}
.cr-map-pin::after {
	content: '';
	position: absolute;
	left: -3px;
	top: -3px;
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: var(--pri-ink);
}

.cr-map-zoom {
	position: absolute;
	right: 10px;
	top: 10px;
	display: flex;
	flex-direction: column;
	gap: 5px;
}
.cr-map-zoom button {
	width: 36px;
	height: 36px;
	border: 1px solid var(--line-strong);
	background: rgba(255,255,255,.94);
	color: var(--text);
	font-size: 19px;
	line-height: 1;
	border-radius: var(--r-sm);
	cursor: pointer;
}

.cr-map-credit {
	position: absolute;
	right: 6px;
	bottom: 4px;
	font-size: 10px;
	color: var(--text-2);
	background: rgba(255,255,255,.85);
	padding: 1px 5px;
	border-radius: 4px;
}

/*
 * A map with no imagery is still a map — the roads, the two people and the
 * scale are all drawn on top and all still true. The surface is darkened a
 * step so the lines and dots have something to sit against once the tiles that
 * used to give them contrast are gone.
 */
.cr-map-dark { background: var(--sunken); }

.cr-map-none {
	position: absolute;
	inset: auto 12px 12px;
	font-size: 12.5px;
	color: var(--text-2);
	background: rgba(255,255,255,.94);
	border: 1px solid var(--line);
	padding: 9px 10px;
	border-radius: var(--r-sm);
	text-align: center;
}

.cr-coords {
	margin-top: 8px;
	font: 12px/1 var(--font-data);
	color: var(--text-2);
	text-align: center;
	font-variant-numeric: tabular-nums;
}
/* The name leads and the numbers follow it. Five decimal places of latitude
   confirm nothing to a person checking they have put the pin on the right
   road; "≈ Kuril" confirms it at a glance — and it is the name the place will
   actually be saved under. */
.cr-coords b {
	display: block;
	margin-bottom: 3px;
	font: 600 13.5px/1.2 var(--font-ui);
	color: var(--text);
}
.cr-coords b:empty { display: none; }

/* ---------------------------------------------------------------- ranges */

.cr-range {
	width: 100%;
	margin: 6px 0 2px;
	accent-color: var(--pri);
	background: transparent;
}

/* ------------------------------------------------------------------ days */

.cr-days { display: flex; gap: 5px; margin-top: 6px; }

.cr-day { flex: 1; margin: 0; }
.cr-day input { position: absolute; opacity: 0; pointer-events: none; }
.cr-day span {
	display: block;
	text-align: center;
	padding: 12px 2px;
	font-size: 12.5px;
	font-weight: 700;
	border: 1px solid var(--line);
	border-radius: var(--r-sm);
	background: var(--sunken);
	color: var(--text-2);
	cursor: pointer;
	min-height: 44px;
	line-height: 20px;
}
/* Filled, not outlined. Six selected days each wearing a ring is six things
   shouting; a filled chip says "on" once and stays quiet. */
.cr-day input:checked + span {
	border-color: var(--pri);
	color: var(--pri-ink);
	background: var(--pri);
}

/* Three chips carrying two words each, so they get a little more room than the
   four one-word ones they replaced — and they never wrap, because a chip that
   goes to two lines stops reading as one choice. */
.cr-when label { padding: 11px 4px; font-size: 12.5px; white-space: nowrap; }

/* Inside a fold the sub-choice is a detail of the mode above it, not a second
   decision of equal weight. */
.cr-fold .cr-choice label { font-size: 12.5px; }

/* ------------------------------------------------------------ share page */

/* Public, no login, no app chrome. Nothing here is an action, so the action
   colour would be a lie — green and neutrals only. */
.cr-share .cr-top { justify-content: center; border-bottom: 0; margin-bottom: 20px; }
.cr-share .cr-card { text-align: center; }
.cr-share .cr-facts { text-align: left; margin-top: 6px; }
.cr-share .cr-facts b { font-size: 13.5px; }
.cr-share-foot {
	margin-top: 18px;
	text-align: center;
	font-size: 11px;
	color: var(--text-3);
}

/* ------------------------------------------------------------ suspended */

/* Every other screen in the app is a top-anchored stack. This one is centred
   on purpose, so it does not read as a page that failed to load. */
.cr-stop {
	min-height: 62vh;
	display: flex;
	flex-direction: column;
	justify-content: center;
}
.cr-stop .cr-card { border-color: var(--alert-edge); }
.cr-stop h2 { color: var(--alert); }

/* ------------------------------------------------------------- tab bar */

/*
 * Home / Activity / Account. One tap back to a known place, from anywhere.
 * Absent on purpose during signup, the camera check and the suspended screen —
 * see shell().
 *
 * A floating bar rather than a full-width strip welded to the bottom edge: it
 * reads as a control sitting on top of the page instead of a border the page
 * ends at, which is what stops a scrolling list feeling cut off.
 */
.cr-tabs {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 40;
	display: flex;
	max-width: 460px;
	margin: 0 auto;
	padding: 6px;
	background: rgba(255, 255, 255, .94);
	backdrop-filter: blur(16px);
	-webkit-backdrop-filter: blur(16px);
	border: 1px solid var(--line);
	border-radius: 26px;
	box-shadow: 0 6px 24px rgba(0,0,0,.13);
	/* Clears the iPhone home indicator, and is simply 0 everywhere else. */
	margin-bottom: calc( 10px + env(safe-area-inset-bottom, 0px) );
	inset-inline: 10px;
}

/* Room to scroll past the bar, so it never covers the last button on a page. */
.cr-wrap.cr-has-tabs { padding-bottom: 96px; }

.cr-tab {
	position: relative;
	flex: 1;
	background: none;
	border: 0;
	padding: 7px 4px 6px;
	color: var(--text-2);
	font: 500 10.5px/1.3 var(--font-ui);
	letter-spacing: .005em;
	cursor: pointer;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 3px;
	min-height: 52px;
	border-radius: 20px;
}

/*
 * The icon sits in its own chip, and only the current tab's chip is filled.
 * One filled thing in the bar, the same rule the rest of the app follows — the
 * old bar coloured the whole active tab amber, which put a second lit lamp on
 * every screen and made the pending dot beside it meaningless.
 */
.cr-tab .cr-ico {
	width: 21px;
	height: 21px;
	padding: 5px 16px;
	box-sizing: content-box;
	border-radius: var(--r-pill);
	stroke-width: 1.9;
}
.cr-tab.cr-on { color: var(--text); font-weight: 650; }
.cr-tab.cr-on .cr-ico { background: var(--line); stroke-width: 2.1; }

/* Something needs answering. A dot, not a number — the count is on the card
   itself, and this only has to say "in here". */
.cr-tab-dot {
	position: absolute;
	top: 5px;
	left: 50%;
	margin-left: 12px;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--signal);
	border: 2px solid var(--surface);
}

/* ------------------------------------------------------- the search pill */

/*
 * "Where to?" — the one entry point the home screen is built around, and the
 * shape the from/to picker uses everywhere else so a destination always looks
 * like a destination. Tapping it expands a list of saved places in place; it
 * does not navigate, because being thrown onto a settings screen to answer
 * "where are you going" is what made this app feel like a form.
 */
.cr-searchpill {
	display: flex;
	align-items: center;
	gap: 12px;
	width: 100%;
	padding: 15px 17px;
	background: var(--sunken);
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	color: var(--text);
	font: 600 16px/1.3 var(--font-ui);
	letter-spacing: -.01em;
	text-align: left;
	cursor: pointer;
	min-height: 56px;
}
.cr-searchpill .cr-ico { width: 20px; height: 20px; color: var(--text-2); }
.cr-searchpill > span {
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.cr-searchpill small { display: block; font-size: 12px; font-weight: 500; color: var(--text-2); margin-top: 1px; }
.cr-searchpill.cr-empty-pill > span { color: var(--text-2); font-weight: 500; }
.cr-searchpill:hover { border-color: var(--line-strong); }
.cr-searchpill[aria-expanded=true] { border-color: var(--text); }

/*
 * The search bar and everything it opens, at the very top of the home screen.
 * When it is shut it is one pill; when it is open it is a text box, the places
 * the geocoder found, and every route already saved.
 */
.cr-hero { margin-bottom: 16px; }

/* Not overflow:hidden, however much the rounded corners want it — the
   geocoder's dropdown is positioned against .cr-search inside here, and
   clipping the panel clips the results to nothing. */
.cr-hero #cr-wherepanel {
	margin-top: 8px;
	border: 1px solid var(--line);
	border-radius: var(--r-card);
	background: var(--surface);
}
.cr-hero .cr-search { margin: 12px 12px 4px; }
.cr-hero .cr-hits { z-index: 20; }
.cr-hero .cr-suggest { padding-bottom: 4px; }

/*
 * The two ends of a journey in one bordered box, origin above destination —
 * the shape every trip planner uses, and the reason it works is that the pair
 * reads as a single question rather than two unrelated dropdowns.
 */
.cr-pillbox {
	margin-top: 8px;
	border: 1.5px solid var(--line-strong);
	border-radius: var(--r-card);
	overflow: hidden;
	background: var(--sunken);
}
.cr-pillbox .cr-endpoint {
	display: flex;
	align-items: center;
	gap: 13px;
	width: 100%;
	padding: 14px 15px;
	background: none;
	border: 0;
	color: var(--text);
	font: 600 15.5px/1.3 var(--font-ui);
	letter-spacing: -.01em;
	text-align: left;
	cursor: pointer;
	min-height: 52px;
}
/* The expanded list sits between the two ends, so this cannot be an adjacent
   sibling rule — the second end still needs its line whether the first end's
   list is open or shut. */
.cr-pillbox > .cr-endpoint:not(:first-child) { border-top: 1px solid var(--line); }
.cr-pillbox .cr-endpoint > span {
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.cr-pillbox .cr-endpoint.cr-unset > span { color: var(--text-2); font-weight: 500; }

/* The end that is not a choice — the pin being placed on the map above. It
   still belongs in the box, because a destination with no origin beside it is
   not a journey. */
.cr-pillbox .cr-endpoint.cr-fixed { cursor: default; }
.cr-pillbox .cr-endpoint[aria-expanded=true] { background: var(--surface); }

/* Ring for where you are, square for where you are going. Same pairing as the
   trip diagram, so the two teach each other. */
.cr-dotmark { width: 11px; height: 11px; flex: none; border-radius: 50%; border: 2.5px solid var(--text-2); }
.cr-dotmark.cr-dest { border: 0; border-radius: 2px; background: var(--text); }

/* The list a pill expands into. In place, under the pill it belongs to. */
.cr-suggest { list-style: none; margin: 0; padding: 4px 0 0; }
.cr-suggest li {
	display: flex;
	align-items: center;
	gap: 13px;
	padding: 12px 15px;
	cursor: pointer;
	border-top: 1px solid var(--line);
	font-size: 14.5px;
}
.cr-suggest li:hover { background: var(--surface); }
.cr-suggest .cr-ico { width: 18px; height: 18px; color: var(--text-2); flex: none; }
.cr-suggest b { font-weight: 600; display: block; }
.cr-suggest small { display: block; color: var(--text-2); font-size: 12px; margin-top: 1px; }
.cr-suggest li.cr-none { color: var(--text-2); font-size: 13px; cursor: default; display: block; }
.cr-suggest li.cr-none:hover { background: none; }

/* A choice the browser has already refused this session. Dimmed rather than
   removed: it may well be fixable, and a row that vanishes reads as a feature
   that is gone rather than one that is being blocked. Still tappable, because
   the person may have just fixed it in another tab. */
.cr-suggest li.cr-off { opacity: .55; }
.cr-suggest li.cr-off small { color: var(--signal); }

/* ----------------------------------------------------------- role toggle */

/*
 * Need a ride / Offering a ride, the way Uber switches between riding and
 * driving. Not an account setting: role in this app lives on the ROUTE, so
 * this only chooses which of your routes the button below acts on. One person
 * can genuinely be both, on different days.
 */
.cr-toggle {
	display: flex;
	gap: 4px;
	padding: 4px;
	background: var(--sunken);
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	margin-bottom: 16px;
}
.cr-toggle button {
	flex: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 7px;
	padding: 10px 8px;
	border: 0;
	border-radius: var(--r-pill);
	background: none;
	color: var(--text-2);
	font: 600 13.5px/1.2 var(--font-ui);
	letter-spacing: -.01em;
	cursor: pointer;
	min-height: 44px;
}
.cr-toggle button .cr-ico { width: 17px; height: 17px; }
.cr-toggle button.cr-on { background: var(--surface); color: var(--text); box-shadow: 0 1px 3px rgba(0,0,0,.14); }

/* -------------------------------------------------------- account rows */

/*
 * The Account tab is a plain vertical list — icon, label, chevron — in small
 * labelled groups. Everything that gets set up once and then never thought
 * about again lives here, which is the only reason the home screen can be one
 * decision wide.
 */
.cr-group {
	font: 700 10.5px/1 var(--font-ui);
	letter-spacing: .13em;
	text-transform: uppercase;
	color: var(--text-3);
	margin: 24px 0 8px;
	padding: 0 2px;
}

.cr-acct { list-style: none; margin: 0; padding: 0; }
.cr-acct > li { border-bottom: 1px solid var(--line); }
.cr-acct > li:last-child { border-bottom: 0; }

.cr-acct button,
.cr-acct .cr-static {
	display: flex;
	width: 100%;
	align-items: center;
	gap: 14px;
	background: none;
	border: 0;
	padding: 15px 2px;
	color: var(--text);
	font: 600 15px/1.35 var(--font-ui);
	letter-spacing: -.01em;
	text-align: left;
	cursor: pointer;
	min-height: 54px;
}
.cr-acct .cr-static { cursor: default; }
.cr-acct .cr-ico { width: 21px; height: 21px; flex: none; color: var(--text); stroke-width: 1.8; }
.cr-acct span.cr-acct-txt { flex: 1 1 auto; min-width: 0; }
.cr-acct small {
	display: block;
	color: var(--text-2);
	font-size: 12.5px;
	font-weight: 400;
	margin-top: 2px;
	line-height: 1.45;
}
.cr-acct .cr-chev { color: var(--text-3); flex: none; }
.cr-acct .cr-chev .cr-ico { width: 16px; height: 16px; color: var(--text-3); }
.cr-acct button:hover { color: var(--text); }
.cr-acct button:hover .cr-chev .cr-ico { color: var(--text-2); }

/* Sign out reads as an ending, not an action to be tempted into. */
.cr-acct .cr-out { padding: 15px 2px; font: 600 15px/1.35 var(--font-ui); color: var(--text-2); }

/* --------------------------------------------------------- account head */

/* Name, university, karma. Lifted wholesale off the home screen, where it was
   the first thing on a screen that is supposed to ask one question. */
.cr-me {
	display: flex;
	align-items: center;
	gap: 12px;
	margin-bottom: 4px;
}
.cr-me .cr-karma { padding: 0 2px 0 0; }
.cr-me .cr-me-txt { flex: 1 1 auto; min-width: 0; }
.cr-me h2 {
	font-size: 26px;
	font-weight: 700;
	letter-spacing: -.035em;
	margin: 0;
	line-height: 1.15;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.cr-me small { display: block; color: var(--text-2); font-size: 13px; margin-top: 3px; }

.cr-mono {
	width: 54px;
	height: 54px;
	flex: none;
	border-radius: 50%;
	background: var(--sunken);
	border: 1px solid var(--line);
	display: grid;
	place-items: center;
	font: 700 22px/1 var(--font-ui);
	color: var(--text-2);
	letter-spacing: -.02em;
}

/* --------------------------------------------------------- signup dots */

.cr-dots { display: flex; gap: 5px; margin: 0 0 14px; }
.cr-dots i {
	width: 100%;
	height: 3px;
	border-radius: 2px;
	background: var(--line);
}
.cr-dots i.cr-on  { background: var(--go-solid); }
.cr-dots i.cr-now { background: var(--signal-solid); }

/* ---------------------------------------------------------- role picker */

.cr-pick { display: flex; flex-direction: column; gap: 10px; margin-top: 18px; }

.cr-pick-one {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 4px;
	width: 100%;
	padding: 17px 16px;
	border: 1px solid var(--line-strong);
	border-radius: var(--r-card);
	background: var(--sunken);
	color: var(--text);
	cursor: pointer;
	text-align: left;
	min-height: 96px;
}
.cr-pick-one .cr-ico { color: var(--text); margin-bottom: 3px; }
.cr-pick-one b { font-size: 16.5px; font-weight: 650; letter-spacing: -.02em; }
.cr-pick-one small { color: var(--text-2); font-size: 13px; line-height: 1.45; }
.cr-pick-one:hover { border-color: var(--text); }

/* -------------------------------------------------------------- a11y ---- */

.cr button:focus-visible,
.cr a:focus-visible {
	outline: 2px solid var(--pri);
	outline-offset: 2px;
}

/* =========================================================================
 * MEETING UP
 *
 * Two visual jobs, and the second matters more than the first. One: draw two
 * people and a pin. Two: make CERTAIN look different from PROBABLY, at arm's
 * length, on a phone in daylight, without reading a word of it — because the
 * decision being made on this screen is whether to step off the kerb.
 *
 * That is what cr-fade and cr-stale are for. They are not decoration; they are
 * the difference between a fix from two seconds ago and one from a minute ago,
 * and they must never be tidied into looking the same.
 * ====================================================================== */

/* Taller than it was. This is the screen's subject, not an illustration beside
   it, and 260 px on a modern handset is a letterbox. Capped against the
   viewport so the read-out under it is never pushed off the bottom. */
.cr-meet-wrap { position: relative; margin: 14px 0 12px; }

/*
 * THE CAP ABOVE WAS REAL AND STILL DID NOT WORK, measured on a 320x568 screen:
 * 46vh is 261px there, which put "740 m away" at y=500 with the tab bar - a
 * fixed overlay - starting at y=482. The read-out was inside the viewport and
 * underneath the navigation, so the one number this whole card exists for was
 * invisible until you thought to scroll a screen that looks complete.
 *
 * 42vh clears it on every phone height from 568 up, and min-height comes down
 * to 200 because a 240px floor puts the same number back under the bar on
 * anything shorter than 572px. Unchanged from 810px up, where the 340 cap binds.
 */
.cr-meet-map {
	height: min(42vh, 340px);
	min-height: 200px;
}

/*
 * AND THEN 1.55.0 SPENT THE FIVE PIXELS.
 *
 * The destination line added to the header costs the card 19px, and the
 * measurement above had exactly 5px of clearance to give: on a 320x568 handset
 * the read-out landed at y=500 with the bar starting at 482, back behind the
 * navigation for the second time.
 *
 * Taken off the map, because the map is the only elastic thing on this card
 * and 204px is still a map, where a distance nobody can see is not a distance.
 * Only on the short phones where the vh cap actually binds - from 640px up the
 * read-out has tens of pixels of slack and the map keeps every one of its own.
 */
@media (max-height: 640px) {
	.cr-meet-map {
		height: min(36vh, 340px);
		min-height: 180px;
	}
}

/* Back to following the two of you. Only shown once the map has been dragged,
   because until then there is nothing to go back to. */
.cr-map-back {
	position: absolute;
	left: 50%;
	bottom: 12px;
	transform: translateX(-50%);
	z-index: 4;
	padding: 8px 15px;
	border-radius: 999px;
	border: 1px solid var(--line-strong);
	background: var(--bg);
	color: var(--text);
	font: 600 12.5px/1 var(--font-ui);
	box-shadow: 0 2px 10px rgba(0,0,0,.16);
	cursor: pointer;
}
.cr-map-back[hidden] { display: none; }

/* The whole journey, on request. Bottom-RIGHT, because Recentre owns the middle
   and the scale bar owns the left — and quieter than both, because it answers a
   question somebody has while waiting, not one they have in a road. */
.cr-map-wide {
	position: absolute;
	right: 10px;
	bottom: 10px;
	z-index: 4;
	padding: 6px 11px;
	border-radius: 999px;
	border: 1px solid var(--line);
	background: rgba(255,255,255,.92);
	backdrop-filter: blur(8px);
	-webkit-backdrop-filter: blur(8px);
	color: var(--text-2);
	font: 600 11.5px/1 var(--font-ui);
	box-shadow: 0 1px 6px rgba(0,0,0,.12);
	cursor: pointer;
}
.cr-map-wide[hidden] { display: none; }

.cr-map-marks { position: absolute; inset: 0; pointer-events: none; }

.cr-mloc {
	position: absolute;
	left: 0;
	top: 0;
	width: 0;
	height: 0;
	/* Linear, and matched to the paint interval. Anything eased reads as the
	   marker accelerating, which is a movement he did not make.

	   On transform rather than left/top: this is the one element on the screen
	   that animates continuously, so it is the one that must not cost a layout
	   per frame. */
	transition: transform .25s linear, opacity .3s ease;
	will-change: transform;
}
.cr-mloc i {
	position: absolute;
	left: -8px;
	top: -8px;
	width: 16px;
	height: 16px;
	border-radius: 50%;
	border: 2px solid var(--bg);
	box-shadow: 0 2px 8px rgba(0,0,0,.45);
}
.cr-mloc b {
	position: absolute;
	left: 12px;
	top: -9px;
	font-size: 11px;
	font-weight: 600;
	white-space: nowrap;
	padding: 2px 6px;
	border-radius: 6px;
	background: var(--bg);
	border: 1px solid var(--line);
	color: var(--text-2);
}

.cr-mloc-pin  i { background: var(--pri); }
.cr-mloc-me   i { background: var(--trust); }
.cr-mloc-them i { background: var(--go-solid); }

/* A suggested meeting point, which is not yet a meeting point. Hollow, in the
   colour of things waiting on somebody's answer: until it is accepted the solid
   black pin is still where both of them are going, and two solid pins on one
   map is two people walking to different corners. */
.cr-mloc-offer i {
	background: var(--bg);
	border: 3px solid var(--signal);
	box-shadow: none;
}

/* WHICH WAY YOU ARE FACING.
 *
 * The map is north-up; a person standing on a pavement is not. An arrow saying
 * "that way" is still a puzzle until you know which way you are pointed, and
 * turning on the spot to work it out is exactly the fumbling this screen exists
 * to remove. Drawn as a cone rather than a needle because a phone compass is
 * worth about fifteen degrees, and a needle claims one. */
.cr-mloc s {
	position: absolute;
	left: -22px;
	top: -22px;
	width: 44px;
	height: 44px;
	border-radius: 50%;
	/* A wedge from the centre, pointing up before rotation. */
	background: conic-gradient(from -28deg,
		rgba(37,99,235,.34) 0deg,
		rgba(37,99,235,.34) 56deg,
		transparent 56deg);
	transition: transform .2s ease-out;
	pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
	.cr-mloc s { transition: none; }
}

/* CLOSE ENOUGH TO LOOK UP.
 *
 * Inside sixty metres the number on the card has stopped being the useful
 * thing — the answer is on the pavement, not the screen. A ring spreading off
 * both dots is the one signal that reads from arm's length, on a phone held low
 * and glanced at rather than studied, and it says "stop reading this" better
 * than any sentence in the space available.
 *
 * On BOTH markers on purpose. One pulsing dot is a notification about somebody
 * else; two is the two of you converging, which is the thing actually happening.
 */
.cr-mloc-close::before {
	content: "";
	position: absolute;
	left: 50%;
	top: 50%;
	width: 18px;
	height: 18px;
	margin: -9px 0 0 -9px;
	border-radius: 50%;
	border: 2px solid currentColor;
	color: var(--trust);
	animation: cr-near 1.8s ease-out infinite;
	pointer-events: none;
}
.cr-mloc-them.cr-mloc-close::before { color: var(--go-solid); }

@keyframes cr-near {
	0%   { transform: scale( .6 ); opacity: .85; }
	100% { transform: scale( 3.4 ); opacity: 0; }
}

/* Motion is the whole mechanism here, so there is no reduced version of it —
   it is replaced with a static ring, which says the same thing quietly. */
@media (prefers-reduced-motion: reduce) {
	.cr-mloc-close::before { animation: none; opacity: .5; transform: scale( 2 ); }
}

/* A label that would land on top of one already placed goes under its dot
   instead. Two names printed over each other are worse than either. */
.cr-mloc b.cr-under { top: 9px; }

/* Stale. The ring stops being solid because the position stopped being known —
   a dashed edge and half opacity say "roughly here" without a sentence. */
.cr-mloc-them.cr-fade { opacity: .55; }
.cr-mloc-them.cr-fade i {
	background: transparent;
	border: 2px dashed var(--go);
	box-shadow: none;
}

.cr-read { min-height: 58px; }

.cr-big {
	font-size: 26px;
	font-weight: 700;
	letter-spacing: -.02em;
	margin: 0 0 4px;
}

/* The ETA, folded into the distance rather than given a sentence of its own.
   Same line, plainly secondary — one is measured, the other is a guess about
   traffic. */
.cr-big .cr-sub {
	font-size: 15px;
	font-weight: 600;
	color: var(--text-3);
	letter-spacing: 0;
}

/* Everything that qualifies the number above it. These were sentences, and the
   sentences were identical every time, so they stopped being read — which is
   the worst possible outcome for the three facts on this screen that say how
   much the distance may be trusted. */
/* The two contact buttons on the meeting screen are anchors, not buttons, so
   the phone opens the dialler and WhatsApp directly. They still have to sit in
   the row like everything else. */
/* Mounted at the top of Activity rather than opened as its own screen. It is
   the same card either way; this only says "you are already where this lives",
   which the missing Back link says too. */
.cr-meet-in { margin-bottom: 14px; }

.cr-meet a.cr-btn {
	display: flex;
	align-items: center;
	justify-content: center;
	text-decoration: none;
}

/* THE WAYS OUT, SMALL.
 *
 * These were four full-width buttons stacked two by two — most of a phone
 * screen given to things used once a ride if at all, while the map and the
 * distance, which are looked at continuously, were pushed off the bottom.
 *
 * Still one tap each and still on THIS screen rather than one back, which was
 * the whole point of putting them here. What they stopped being is the biggest
 * thing on it. Five across at 360px is 64px each — comfortably past the 44px
 * a thumb needs, which is the floor that decides this row's size, not taste. */
.cr-ways {
	display: flex;
	gap: 6px;
	margin-top: 12px;
}
.cr-way {
	flex: 1 1 0;
	min-width: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 3px;
	padding: 8px 2px 7px;
	border: 1px solid var(--line);
	border-radius: 12px;
	background: var(--surface);
	color: var(--text-2);
	font: inherit;
	font-size: 11px;
	font-weight: 600;
	text-decoration: none;
	cursor: pointer;
	transition: background .12s, border-color .12s, color .12s;
}
.cr-way span {
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.cr-way .cr-ico { width: 19px; height: 19px; }
.cr-way:hover { color: var( --text ); border-color: var(--line-strong); background: var(--sunken); }

/* WhatsApp keeps its colour, because it is the one people look for by colour
   rather than by reading the row. */
.cr-way-wa { color: var(--go); border-color: var(--go-edge); background: var(--go-tint); }
.cr-way-wa:hover { color: var(--go); border-color: var(--go); background: var(--go-tint); }

/* Which kerb. The one line on this screen that stops somebody standing on the
   wrong side of a divider watching their lift go past, so it is given the
   weight of an instruction rather than of a note. */
.cr-side {
	display: flex;
	align-items: center;
	gap: 6px;
	margin-top: 6px;
	font-weight: 600;
	color: var(--text);
}
.cr-side .cr-ico { width: 1.05em; height: 1.05em; flex: none; color: var(--text-2); }

/* TYPING TO EACH OTHER. This replaced six fixed phrases, which were one tap and
   had nothing to moderate — a real thing to have given up. But six sentences
   cannot carry "behind the blue CNG by the pharmacy", and that is the sentence
   that ends the search rather than prefacing a phone call. */
.cr-chat { margin-top: 10px; }

/* Capped and scrolling. This card is already long and the conversation is the
   one part of it with no upper bound, so it is given a window rather than
   allowed to push the map and the buttons off the screen. */
.cr-chat-log {
	max-height: 168px;
	overflow-y: auto;
	overscroll-behavior: contain;
	-webkit-overflow-scrolling: touch;
	display: flex;
	flex-direction: column;
	gap: 5px;
	/* Room for the scrollbar to live in, on the right only.
	 *
	 * The old `padding: 2px 1px` left a right-aligned bubble ONE PIXEL from the
	 * scrollbar. That is invisible in a headless browser, which draws scrollbars
	 * as an overlay — and a 15 px trough with arrow buttons on Windows Chrome,
	 * where the arrows then sit on top of the bubble's corner. `stable` keeps
	 * the gutter reserved whether or not the bar is showing, so the thread does
	 * not reflow the moment it grows past the fourth message. */
	scrollbar-gutter: stable;
	scrollbar-width: thin;
	padding: 8px 10px;

	/* A boundary. Without one, a scrollbar appears floating in blank space
	   between two half-cut bubbles, and the whole card reads as broken layout
	   even when it is scrolling perfectly. */
	border: 1px solid var(--line);
	border-radius: var(--r-card);
	background: var(--bg);
}
.cr-chat-log:empty { display: none; }

/* A conversation taller than its window is fine; a message sliced across the
   top edge looks like a rendering fault. The fade says "there is more up
   there" in a way a hard cut cannot. */
.cr-chat-log { mask-image: linear-gradient( to bottom, transparent 0, #000 10px ); }
.cr-chat-log { -webkit-mask-image: linear-gradient( to bottom, transparent 0, #000 10px ); }

.cr-chat-log p {
	margin: 0;
	max-width: 82%;
	padding: 7px 11px;
	border-radius: 14px;
	font-size: 14px;
	line-height: 1.4;
	word-wrap: break-word;
	overflow-wrap: anywhere;
}
.cr-msg-them {
	align-self: flex-start;
	background: var(--sunken);
	border: 1px solid var(--line);
	border-bottom-left-radius: 5px;
	color: var(--text);
}
.cr-msg-me {
	align-self: flex-end;
	background: var(--pri);
	border-bottom-right-radius: 5px;
	color: var(--pri-ink);
}

/* Gone, not yet acknowledged. Faded rather than marked with a tick, because a
   tick claims delivery and nothing here can honestly claim it. */
.cr-msg-wait { opacity: .55; }

.cr-chat-say {
	display: flex;
	gap: 7px;
	margin-top: 8px;
}
.cr-chat-say input {
	flex: 1 1 auto;
	min-width: 0;
	min-height: 42px;
	padding: 9px 13px;
	border-radius: 999px;
	border: 1px solid var(--line);
	background: var(--sunken);
	color: var(--text);
	font: inherit;
	font-size: 15px;   /* never below 15px: iOS zooms the page on focus */
}
.cr-chat-say input:focus {
	outline: none;
	border-color: var(--pri);
	background: var(--surface);
}
.cr-chat-send {
	flex: none;
	width: 42px;
	height: 42px;
	display: grid;
	place-items: center;
	border: 0;
	border-radius: 50%;
	background: var(--pri);
	color: var(--pri-ink);
	cursor: pointer;
}
.cr-chat-send:hover { background: var(--pri-hover); }

.cr-read .cr-tags { margin-top: 8px; }
.cr-tag-warn {
	border-color: var(--signal-edge);
	color: var(--signal);
}

/* "At the pin", while you are. A pressed state rather than a second label to
   read: the button is the switch and its own indicator. */
.cr-meet .cr-btn.cr-on {
	background: var(--go-tint);
	border-color: var(--go-edge);
	color: var(--go);
}
.cr-big.cr-good-t { color: var(--go); }
.cr-big.cr-stale  { color: var(--text-3); }
p.cr-tight.cr-stale { color: var(--signal); }

/*
 * WHERE THE RIDE ENDS, in the header, without costing the read-out its place.
 *
 * The vertical budget on this card is spent to the last pixel: on a 320x568
 * handset the distance sits at y=477 with the fixed tab bar starting at 482,
 * so a second line here is five pixels away from hiding the one number the
 * screen exists for. Quieter and tighter than the line above it, and held to
 * one line - a wrap costs seventeen pixels there is no room for, and the
 * destination's first words are the part worth reading.
 */
.cr-meet-off {
	font-size: 11.5px;
	margin-top: 1px;
	color: var(--text-3);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Where the ride ends and how far that leaves somebody from where they were
   actually going. Quiet, because it is a fact about the ride rather than
   anything to act on — but the place name is bold, because on a card full of
   times and distances it is the only word. */
.cr p.cr-drop-to {
	margin: 10px 0 0;
	font-size: 12.5px;
	line-height: 1.5;
	color: var(--text-2);
}
.cr p.cr-drop-to b { color: var(--text); font-weight: 650; }

/*
 * Which of the two phones is doing the reporting, on a running ride. Quieter
 * than everything around it on purpose: it explains a battery, it is not a
 * thing anybody has to act on, and a pillion who never reads it loses nothing.
 */
p.cr-relay { color: var(--muted); font-size: 13px; margin: 6px 0 0; }

.cr-close-up {
	margin: 12px 0 4px;
	padding: 14px;
	border-radius: var(--r-card);
	background: var(--go-tint);
	border: 1px solid var(--go-edge);
	text-align: center;
}

/* The plate is the thing that actually identifies the bike, so below a hundred
   metres it gets the size the map had. */
.cr-plate-big {
	font-size: 30px;
	font-weight: 800;
	letter-spacing: .08em;
	margin: 6px 0 2px;
	font-variant-numeric: tabular-nums;
}

/* Held up across a road. Deliberately the whole screen — a coloured card in a
   crowd is a coloured card; a whole phone is a beacon. */
.cr-flash {
	position: fixed;
	inset: 0;
	z-index: 9999;
	animation: cr-pulse 1s steps(1) infinite;
}
@keyframes cr-pulse {
	50% { filter: brightness(.25); }
}

/* No drop-pin on this map. Everywhere else the centre pin means "wherever you
   drag to"; here nothing is being chosen, and a second pin-shaped thing beside
   two real markers reads as a third person. */
.cr-meet-map .cr-map-pin { display: none; }

/* Except while the map IS the question. Dragging to a better corner needs the
   same centre pin every other picker on this app uses, and needs the map to
   read as an instrument rather than a picture. */
.cr-meet-map.cr-moving .cr-map-pin { display: block; }
.cr-meet-map.cr-moving { border-color: var(--signal); box-shadow: inset 0 0 0 2px var(--signal-tint); }

/* Moving the meeting point. One block, three states, and never two at once —
   a suggestion to accept, a suggestion sent, or a map being dragged. */
.cr-move {
	margin-top: 10px;
	padding: 11px 12px;
	border-radius: var(--r-card);
	border: 1px solid var(--line);
	background: var(--sunken);
}
.cr-move p { margin: 0 0 9px; font-size: 14px; line-height: 1.45; }
.cr-move .cr-row { margin: 0; }

/* Theirs, unanswered. The only thing on this screen that requires an answer
   before the map means what it says, so it is the only one tinted. */
.cr-move-ask {
	border-color: var(--signal-edge);
	background: var(--signal-tint);
}
.cr-move-wait p { color: var(--text-2); }
.cr-move-wait .cr-link { padding: 12px 0; min-height: 44px; }

/* The pin is following her. Stated quietly rather than tinted — this is the
   normal condition of her screen, not something needing an answer, and a box
   that shouts on every ride stops being read by the second one. It still says
   it, because she did not choose it and the rider has her exact position. */
.cr-move-follow p,
.cr-move-held p { color: var(--text-2); display: flex; gap: 7px; align-items: flex-start; }
.cr-move-follow svg { flex: none; margin-top: 2px; opacity: .75; }
/* "I will wait right here" freezes the meeting point for both of them. It was a
   19px-tall strip, which is the smallest target on the screen attached to the
   largest consequence on it. */
.cr-move-follow .cr-link,
.cr-move-held .cr-link { padding: 12px 0; min-height: 44px; }

/* Held. She has stopped and said so, which is a real state of the ride and the
   one he can plan a turn into — so unlike following, it is worth a colour. */
.cr-move-held {
	border-color: var(--go-edge);
	background: var(--go-tint);
}

#cr-meet-move > .cr-link { margin-top: 6px; }

/* The pillion is usually standing ON the meeting point, so these two labels
   land on top of each other. Lift the pin's clear of the marker's. */
.cr-mloc-pin b { top: -26px; left: -18px; }

/* WHERE THE RIDE ENDS, drawn but never framed — so for most of the wait this
   sits off the edge, and when it is on screen it must not read as somewhere
   anybody is going now. Hollow, and the same violet as the route it belongs to
   rather than the black of the meeting pin, which IS somewhere to go. */
.cr-mloc-far i {
	background: var(--bg);
	border: 2.5px solid var(--route);
	box-shadow: 0 1px 5px rgba(0,0,0,.3);
}
.cr-mloc-far b {
	background: rgba(255,255,255,.9);
	color: var(--text-2);
	font-weight: 600;
}

/* The uncertainty band. Sized in metres by map.js and converted at the current
   zoom, so it always means the same distance on the ground.

   It is drawn on ::after rather than as a fourth marker so it can never be
   mistaken for a person, and it only appears once a reading has gone stale —
   a circle around a live fix would imply doubt that is not there. */
.cr-mloc-them::after,
.cr-mloc-me::after {
	content: '';
	position: absolute;
	left: 50%;
	top: 50%;
	width: calc(var(--haze, 0px) * 2);
	height: calc(var(--haze, 0px) * 2);
	margin: calc(var(--haze, 0px) * -1) 0 0 calc(var(--haze, 0px) * -1);
	border-radius: 50%;
	background: var(--go-tint);
	border: 1px solid var(--go-edge);
	transition: width .4s linear, height .4s linear, margin .4s linear;
	pointer-events: none;
}

/*
 * A GUESS HAS TO LOOK LIKE A GUESS.
 *
 * Past cr-dead there is no reading any more — only the last place they were
 * seen, and a circle of everywhere they could have reached since. A solid pin
 * in the middle of that says "he is here", which is precisely what it does not
 * mean, and it is the sentence that gets somebody to step off a kerb.
 *
 * So the centre goes hollow and the edge goes dashed. Nobody has to be taught
 * what a dashed circle means; they have to be taught what a confident dot in
 * the middle of a vague halo means, and they will learn it the wrong way.
 */
.cr-mloc-guess {
	background: transparent;
	border-style: dashed;
	box-shadow: none;
}

.cr-mloc-guess::after {
	border-style: dashed;
	background: transparent;
}

/* The same circle for your own fix, in your own colour. It appears only when
   the phone admits to more than about thirty metres of doubt — below that it
   would be smaller than the dot and would say nothing. */
.cr-mloc-me::after {
	background: rgba(37,99,235,.10);
	border-color: rgba(37,99,235,.34);
}
