/* Round 33 · Lull (forked from winter32.css): the melt's mask, at the foot. */
/* Round 31 · styles for 48-glaze (forked from Round 30's winter30.css): Round 21's tap spot, quieter;
   his portrait opened without its mount; Stack + pair, his pick, the one phone card.
   Round 30 · styles for 47-rime (forked from Round 29's winter29.css): Drift out set as Split is until
   it goes; an opened card on a phone, Stacked with its description above the numbers, Pairs, and three
   ways between them, on Search's results as on About's (the mcard switch).
   Round 29 · styles for 46-powder (forked from Round 28's winter28.css): three versions of Drift that
   leave by the corners (they rest as Split does until they go); the caret steady while his question
   is typed; and an opened card on a phone laid out one of five ways (the mcard switch).
   Round 28 · styles for 45-powder (forked from Round 27's winter27.css): three experiments in the
   direction of Split (Drift, Thread, Stairs).
   Round 27 · styles for 44-powder (forked from Round 26's winter26.css): Search in the story at
   night too, over the dark and the snow; a cleaner fall into the night; the closing line's highlighter
   for the dark.
   Round 26 · styles for 43-powder (forked from Round 25's winter25.css): Search full-screen in the
   story instead of on a phone; his belief sentence five ways; the story at night (an option).
   Round 25 · styles for 42-powder (forked from Round 24's winter24.css): unchanged but for the fork.
   Round 24 · styles for 41-powder (forked from Round 23's winter23.css): unchanged but for the fork.
   Round 23 · styles for 40-powder (forked from Round 22's winter22.css): LIFESCI 15's opened lines
   with Search's own labels; the rest as Round 22.
   Round 22 · styles for 39-powder (forked from Round 21's winter21.css): Search's question without
   the highlighter (the phone leans in toward it instead, winter22.js); LIFESCI 15 opened to its
   description, three plain lines and its GE.
   Round 21 · styles for 38-powder (forked from Round 20's winter20.css): why he made this in one
   block, or two spaced further apart; Search's question marked by a highlighter, a finger's taps,
   and LIFESCI 15 opened on the phone; "Fulong, Taiwan" in proportion to the print, as Round 14 had
   it; on a phone, Search's brand as low as the conversation's, clear of the screen's corner.
   Round 20 · styles for 37-powder (forked from Round 19's winter19.css): About in Anthony's Round 20
   order, told three ways (the tell switch): why he made this in two lines, one at the left and one at
   the right, before Search on a phone that shows only the question and its answers; "Fulong, Taiwan"
   down his portrait's right edge again, as in Round 14; no sound switch.
   Round 19: About in his new words; Search on the realistic phone alone, nothing at its foot; his
   portrait small again.
   Round 18: About told the Focus way only, moved on by a small swipe; Search typed and answered on a
   live phone, minimal or realistic; sound; his portrait opens.
   Round 17: About's story on one held screen, a scene at a time, with Search alive on a phone; the
   brand is the way back.
   Round 16: About's story from Anthony's notebook, and Search's way back as an arrow.
   Phone rules are container queries on #page, so a 390px frame shows the real phone layout. */
:root {
  color-scheme: light;
  --paper: #FCFBF8; --surface: #FFFFFF; --ink: #16334F; --muted: #5D7186; --soft: #8C9BAA;
  --blue: #2774AE; --blue-ink: #1D5E90; --gold: #FFD100; --gold-soft: rgba(255,209,0,.34); --green: #5E8A3A;
  --crust: #9A5B22; --crust-ink: #6E3F14; --crust-soft: rgba(176,112,48,.14);
  --bg: var(--paper); --tone: #EEF2F6; --tone-2: #E4EAF0; --bubble: #E8EFF5;
  --hero-ink: var(--ink); --label-ink: var(--ink); --label-sub: var(--muted); --line-ink: rgba(22,51,79,.62); --end-fill: var(--surface);
  --bar-ink: var(--ink);
  --f-display: "Bricolage Grotesque", "Instrument Sans", system-ui, sans-serif;
  --f-body: "Instrument Sans", -apple-system, "Segoe UI", Roboto, sans-serif;
  --hero-w: 700; --hero-size: clamp(34px, 5.2vw, 54px); --hero-track: -.022em; --hero-lh: 1.06;
  --ease: cubic-bezier(.16, 1, .3, 1);
  --gutter: max(16px, env(safe-area-inset-left, 0px));
  --field-r: 14px; --btn-r: 10px; --card-r: 10px;
  /* Round 34: main's hairline, soft blue and mono, for the conversation's foot and note. */
  --line: #DEE4E9; --blue-soft: rgba(39,116,174,.09);
  --f-mono: "Spline Sans Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}
* { box-sizing: border-box; margin: 0; }
html, body { overflow-x: clip; } html { -webkit-text-size-adjust: 100%; }
body { min-height: 100svh; background: var(--bg); color: var(--ink); font: 16px/1.6 var(--f-body); -webkit-tap-highlight-color: transparent; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; touch-action: manipulation; padding: 0; }
a { color: inherit; }
img { display: block; max-width: 100%; }
:is(button, textarea, input, a, [tabindex]):focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: 6px; }
::selection { background: var(--gold-soft); }
[hidden] { display: none !important; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

/* ---------- Layers ---------- */
canvas.sky { position: absolute; top: 0; left: 0; z-index: 0; pointer-events: none; }
canvas.snow { position: fixed; inset: 0; pointer-events: none; }
#snow-back { z-index: 0; } #snow-front { z-index: 8; }
#page { position: relative; z-index: 1; container: page / inline-size; overflow-x: clip; }
[data-view] { position: relative; padding-inline: var(--gutter) max(16px, env(safe-area-inset-right, 0px)); }
.perch { position: absolute; pointer-events: none; z-index: 2; }

/* ---------- Header ---------- */
.bar { width: 100%; max-width: 1080px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 66px; padding-top: env(safe-area-inset-top, 0px); color: var(--bar-ink); position: relative; z-index: 9; }
.brand { display: flex; align-items: center; gap: 8px; font: 600 17px/1 var(--f-display); text-decoration: none; letter-spacing: -.01em; }
.brand svg { width: 24px; height: 24px; color: var(--gold); transform: rotate(-18deg); }
.bar-end { display: flex; align-items: center; gap: 10px; }
.me { display: block; padding: 4px; border-radius: 4px; }
.me .print { display: block; width: 38px; padding: 3px 3px 9px; background: var(--surface); border-radius: 1px; box-shadow: 0 1px 2px rgba(22,51,79,.2), 0 6px 12px -8px rgba(22,51,79,.5); transform: rotate(5deg); transition: transform .5s var(--ease); } /* taste-skill-ignore: a printed photo, as chosen in Round 8 */
.me .print img { width: 32px; height: 36px; object-fit: cover; object-position: 50% 35%; }
.me:hover .print, .me:focus-visible .print { transform: rotate(0) translateY(-2px); }
/* Round 17: on a pointer device it hangs on a pin and swings (winter17.js Swing); GSAP moves it. */
.swing-js .me .print { transition: none; }
.icon-btn { width: 38px; height: 38px; display: grid; place-items: center; border-radius: 10px; color: var(--bar-ink); opacity: .75; transition: opacity .2s, background-color .2s; }
.icon-btn svg { width: 20px; height: 20px; }
.icon-btn:hover { opacity: 1; background: rgba(127,150,175,.14); }

/* ---------- Landing ---------- */
.landing { max-width: 1080px; margin: 0 auto; padding-top: clamp(14px, 4.5vh, 52px); }
.scene { position: relative; }
#hero { position: relative; font-family: var(--f-display); font-weight: var(--hero-w); font-size: var(--hero-size); line-height: var(--hero-lh); letter-spacing: var(--hero-track); text-align: center; text-wrap: balance; color: var(--hero-ink); z-index: 6; }
.hl { position: relative; white-space: nowrap; isolation: isolate; }
.hl::after { content: ""; position: absolute; left: -.06em; right: -.04em; bottom: .05em; height: .36em; background: var(--gold-soft); z-index: -1; border-radius: 2px; transform-origin: left; animation: swipe .9s .35s var(--ease) backwards; }
@keyframes swipe { from { transform: scaleX(0); } }
.stage { position: relative; margin-top: clamp(16px, 3.6vh, 38px); }
.plate { position: relative; }
.landmark { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
.landmark img { position: absolute; max-width: none; }
[data-ucla="royce"] .landmark .bear, [data-ucla="bear"] .landmark .royce, [data-ucla="none"] .landmark img { display: none; }
.specimen { position: absolute; top: 0; left: 0; z-index: 4; }
/* Until landing.js first lays the plate out (layoutOnce gives #specimen its inline size), the bunch
   showed at its image's own 630x662 in the plate's corner, and the heading and Ask bar sat too high
   (Anthony: "the banana is huge and positioned at the bottom-left corner before snapping back").
   Till then it holds the room layoutOnce will give it, unseen: 336px or 60% (a phone: 70% or 290px),
   shrunk on a short screen as FIT does, with the labels' rows above and below it on a phone. */
.specimen:not([style]) { position: relative; visibility: hidden; aspect-ratio: 630 / 662; margin: 10px auto 27px; width: min(336px, 60%, (100svh - 312px) * 630 / 662); }
.plate:has(> .specimen:not([style])) { display: flow-root; }   /* its margins stay inside the plate */
@container page (max-width: 760px) { .specimen:not([style]) { margin: 101px auto 80px; width: min(70%, 290px, (100svh - 463px) * 630 / 662); } }
.bunch { width: 100%; height: 100%; transform-origin: 62% 4%; }
.bunch img { width: 100%; height: 100%; object-fit: contain; cursor: pointer; }
.leaders { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; z-index: 7; }
.leaders .ink { fill: var(--line-ink); transition: fill .25s; }
.leaders .trace { display: none; }
.leaders .end { fill: var(--end-fill); stroke: var(--label-ink); stroke-width: 1.1; transition: r .3s var(--ease), fill .2s; }
.leaders .start { fill: var(--label-ink); }
.leaders g.on .ink { fill: var(--label-ink); }
.leaders g.on .end { fill: var(--gold); r: 6px; }
.leaders g.soon { opacity: .5; }
.label { position: absolute; top: 0; display: grid; justify-items: start; gap: 2px; width: max-content; max-width: 236px; padding: 4px 2px; border-radius: 6px; text-align: left; z-index: 8; color: var(--label-ink); }
.label.end-align { text-align: right; justify-items: end; }
.label b { font-weight: 600; font-size: 16.5px; line-height: 1.3; letter-spacing: -.005em; background: linear-gradient(var(--gold-soft), var(--gold-soft)) left 88% / 0 38% no-repeat; transition: background-size .3s var(--ease); } /* taste-skill-ignore: a flat highlighter stroke, not a gradient fill */
.label.end-align b { background-position: right 88%; }
.label.on b { background-size: 100% 38%; }
.label small { font-size: 14px; line-height: 1.4; color: var(--label-sub); }
/* Degree Auditing, not ready yet: greyed by colour, not opacity. Round 15 greys the whole label a
   step further (Anthony: "slightly more greyed out"): its name still reads at 4.5:1 on the sky, its
   line at about 4:1, as a feature that isn't open yet. Round 11's .62 opacity left 2.4–3.9:1. */
.label[data-k="3"] { --label-ink: #5D7084; }
.label[data-k="3"] small { color: #6A7C8F !important; }
.label .sub-p { display: none; }
.plate.phone .label .sub-p { display: inline; }
.plate.phone .label .sub-d { display: none; }
.plate.phone .label { max-width: 170px; }
.plate.phone .label b { font-size: 15px; }
.plate.phone .label small { font-size: 13px; }

/* The composer: production's writing line. */
.ask-wrap { position: relative; z-index: 6; max-width: 660px; margin: clamp(30px, 5.5vh, 60px) auto 0; }
form.composer { position: relative; display: flex; align-items: flex-end; gap: 14px; border-bottom: 2px solid var(--rule, rgba(22,51,79,.3)); padding-bottom: 8px; transition: border-color .2s; }
form.composer:focus-within { border-color: var(--gold); }
form.composer textarea:focus-visible { outline: none; }
textarea { flex: 1; min-width: 0; resize: none; overflow: hidden; border: 0; background: transparent; font: inherit; font-size: 17px; line-height: 26px; height: 26px; color: inherit; outline: none; border-radius: 0; }
textarea::placeholder { color: var(--muted); opacity: .9; }
textarea:focus::placeholder { color: transparent; }
.send { display: flex; align-items: center; gap: 7px; color: var(--blue); font-weight: 600; font-size: 15px; padding: 4px 0 2px; }
.send svg { width: 13px; height: 13px; }
.send:hover { color: var(--blue-ink); }
.hint { position: absolute; left: 0; right: 70px; bottom: 10px; font-size: 17px; line-height: 26px; color: var(--muted); pointer-events: none; opacity: 0; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; }
.hint.on { opacity: .9; }

/* ---------- Conversation ---------- */
#chat { min-height: 100svh; display: flex; flex-direction: column; }
.thread { width: 100%; max-width: 700px; margin: 0 auto; padding: clamp(18px, 4vh, 40px) 0 140px; flex: 1; }
.turn + .turn { margin-top: 40px; }
.q { display: flex; justify-content: flex-end; }
.q p { max-width: min(82%, 560px); background: var(--bubble); color: var(--ink); padding: 10px 17px; border-radius: 18px; font-size: 16px; line-height: 1.55; }
.a { margin-top: 20px; }
.answer { font-size: 16px; line-height: 1.65; color: var(--ink); }
.answer p + p, .answer ul + p, .answer p + ul { margin-top: 10px; }
.answer ul { padding-left: 22px; display: grid; gap: 6px; }
.answer li::marker { color: var(--muted); }
/* Round 39: the reveal shows a paragraph, bullet or course label only once its words reach it (chat.js). */
.answer .unseen { display: none; }
.answer b { font-weight: 600; }
.loader svg { width: 30px; height: 30px; fill: none; stroke: var(--ink); stroke-width: 1.5; stroke-linecap: round; animation: flake 3.2s linear infinite; }
/* Round 44: the breath shrinks the flake about its own centre, (0, 0) in its viewBox. "center" on an
   SVG group is the middle of a box that starts at (0, 0), so the flake had shrunk toward its lower
   right, sliding down about 4.6px a breath. */
.loader svg g { animation: breathe 1.6s ease-in-out infinite; transform-origin: 0 0; }
@keyframes flake { to { transform: rotate(60deg); } }
@keyframes breathe { 50% { opacity: .35; transform: scale(.8); } }
/* Round 34: the conversation's foot is main's again (Anthony: "The grounding labels are also too big
   and noisy… use the example of what's been done before"). A course's label in an answer is main's
   inline catalog cross-reference: the code in the small mono, blue ink, a dotted rule under it. */
.ref { font-family: var(--f-mono); font-weight: 500; font-size: .8em; letter-spacing: .03em; color: var(--blue-ink); padding: 0 2px 1px; border-bottom: 1px dotted rgba(39,116,174,.55); border-radius: 3px 3px 0 0; white-space: nowrap; transition: background-color .15s, border-color .15s; }
.ref:hover { background: var(--gold-soft); border-bottom-color: transparent; }
/* Sources on the left and the two thumbs on the right, one line (main's .msg-foot). */
.msg-foot { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; column-gap: 14px; margin-top: 16px; }
.msg-foot:not(:has(details.sources)) { margin-top: 8px; }
/* The open list runs the answer's full width; the thumbs keep to the label's line beside it. */
.msg-foot details.sources { grid-row: 1; grid-column: 1 / -1; min-width: 0; }
details.sources > summary { list-style: none; display: flex; width: fit-content; align-items: center; gap: 7px; cursor: pointer; font-family: var(--f-mono); font-weight: 500; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); user-select: none; line-height: 1.6; }
details.sources > summary:hover { color: var(--blue-ink); }
details.sources > summary::-webkit-details-marker { display: none; }
details.sources > summary::before { content: ""; width: 6px; height: 6px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(-45deg); transition: transform .15s; margin-top: -2px; }
details.sources[open] > summary::before { transform: rotate(45deg); margin-top: -4px; }
/* A GE is one unit: it moves to the next line whole, two to a line where they fit, and wraps inside
   only if it is longer than a whole line. */
.ge-u { display: inline-block; max-width: 100%; }
/* Round 35 (Anthony: "This looks nothing like the sources panel I had from my stable deploy before
   today. Go to that… and re-use its version but with the same internal card layout as we have now"):
   main's panel as it was (e2d82ea): each answer in its ruled catalog margin, and the Sources in the
   foot's left column, the thumbs beside them, as compact white cards of 13.5px text. Inside each card,
   About's layout, as the Sources had it after Round 34: the code and name at the head, then small
   grey labels over their values (across on a desktop, About's phone pairs on a phone). */
#thread .turn > .a { border-left: 2px solid var(--line); padding-left: 18px; }
html[data-rule="off"] #thread .turn > .a { border-left: 0; padding-left: 0; }
.source-list { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.source-card { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: 13px 16px 12px; font-size: 13.5px; line-height: 1.55; box-shadow: 0 1px 3px rgba(22,51,79,.08); }
.source-card.flash { animation: src-flash 1.4s ease-out; }
@keyframes src-flash { 0% { background: var(--gold-soft); border-color: var(--gold); } }
.source-card .entry-head { display: flex; align-items: baseline; flex-wrap: wrap; column-gap: 10px; margin-bottom: 8px; }
.source-card .code { font-family: var(--f-mono); font-weight: 500; font-size: 12px; letter-spacing: .05em; color: var(--blue-ink); }
.source-card .name { font-family: var(--f-display); font-weight: 600; font-size: 15px; letter-spacing: -.01em; }
.source-card .secs { font-size: 12px; color: var(--muted); }
/* The fields, whatever the Search card switches say: a phone's pairs first (Professor | Meets, the
   description, Bruinwalk | A%, the GEs), a desktop's row across below. */
#thread .source-card .fields { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 18px; row-gap: 9px; font-size: 13.5px; line-height: 1.5; max-width: none; }
#thread .source-card .fields > div { display: grid; align-content: start; gap: 1px; grid-column: 1 / -1; }
#thread .source-card .fields dt { display: block; font-size: 11.5px; line-height: 1.45; font-weight: 500; letter-spacing: .02em; color: var(--muted); }
#thread .source-card .fields dt::after { content: none; }
#thread .source-card .fields dd { display: block; color: var(--ink); }
#thread .source-card .fields > .f-desc dd { line-height: 1.55; }
#thread .source-card .fields > .f-prof { order: 1; grid-column: auto; }
#thread .source-card .fields > .f-meets { order: 2; grid-column: auto; }
#thread .source-card .fields > .f-desc { order: 3; }
#thread .source-card .fields > .f-bw { order: 4; grid-column: auto; }
#thread .source-card .fields > .f-a { order: 5; grid-column: auto; }
#thread .source-card .fields > .f-ge { order: 6; }
/* The thumbs: main's pencil marks in the margin, quiet grey, on the newest answer and on hover. */
.feedback { grid-row: 1; grid-column: 2; align-self: start; display: flex; gap: 2px; margin: -3px -6px 0 0; opacity: 0; transition: opacity .15s; }
.a:is(:hover, :focus-within, .is-latest) .feedback, .feedback.has-vote { opacity: 1; }
@media (hover: none) { .feedback { opacity: 1; } }
.thumb { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 24px; border-radius: 6px; color: var(--muted); opacity: .7; transition: color .15s, background-color .15s, opacity .15s; }
.thumb svg { width: 15px; height: 15px; }
.thumb.is-down svg { transform: scale(-1); }
.thumb:hover { color: var(--ink); opacity: 1; }
.thumb[aria-pressed="true"] { color: var(--ink); opacity: 1; background: var(--gold-soft); }
.feedback.is-final .thumb { cursor: default; }
.feedback.is-final .thumb[aria-pressed="false"] { opacity: .3; color: var(--muted); }
/* The note: main's banana that ripens as you write and bakes into banana bread ("Banana Bread
   Fold-away", PR #4), as it was. */
.fb-note { --stage-color: var(--line); --stage-ink: var(--muted); max-width: 560px; margin-top: 18px; display: grid; grid-template-columns: 58px minmax(0, 1fr); column-gap: 12px; row-gap: 2px; animation: note-in .5s cubic-bezier(.22,1,.36,1) backwards; }
@keyframes note-in { from { opacity: 0; transform: translateY(12px); } }
.fb-note.is-leaving { animation: note-out .22s ease-in forwards; }
@keyframes note-out { to { opacity: 0; transform: translateY(8px); } }
.fb-slot { position: relative; grid-row: 1 / span 3; width: 50px; height: 90.67px; }
.fb-nana { position: absolute; inset: 0; }
.fb-nana i, .fb-bake i { position: absolute; inset: 0; background-repeat: no-repeat; }
.fb-nana i { background-image: url("/frontend/img/banana-ripen.webp"); background-size: 600% 100%; background-position: calc(var(--i) * 20%) 0; transition: opacity .18s linear; }
.fb-bake { position: absolute; pointer-events: none; }
.fb-bake i { background-image: var(--strip); background-size: calc(var(--n) * 100%) 100%; background-position: calc(var(--i) * 100% / (var(--n) - 1)) 0; opacity: 0; }
.fb-steam { position: absolute; overflow: visible; pointer-events: none; }
.fb-steam path { fill: none; stroke: rgba(93,113,134,.5); stroke-width: 1.8; stroke-linecap: round; }
.fb-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.fb-q { padding-top: 2px; font-family: var(--f-display); font-weight: 600; font-size: 16px; letter-spacing: -.01em; line-height: 1.3; }
.fb-x { flex: none; width: 26px; height: 26px; display: grid; place-items: center; border-radius: 6px; color: var(--muted); opacity: .55; transition: opacity .15s, color .15s; }
.fb-x:hover { opacity: 1; color: var(--ink); }
.fb-field { padding: 6px 0; border-bottom: 2px solid var(--line); transition: border-color .25s; }
.fb-note.is-writing .fb-field { border-color: var(--stage-color); }
.fb-note textarea:focus-visible { outline: none; }
.fb-note textarea { display: block; width: 100%; margin: 0; padding: 0; border: 0; border-radius: 0; resize: none; outline: none; -webkit-appearance: none; appearance: none; background: transparent; color: var(--ink); font: inherit; font-size: 17px; line-height: 1.55; overflow-y: hidden; }
.fb-foot { grid-column: 2; display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 32px; padding-top: 4px; }
.fb-ripe { font-family: var(--f-mono); font-weight: 500; font-size: 10.5px; letter-spacing: .1em; line-height: 1.4; text-transform: uppercase; color: var(--muted); transition: color .25s; }
.fb-note.is-writing .fb-ripe { color: var(--stage-ink); }
.fb-note.is-filed .fb-ripe { color: var(--muted); }
.fb-file { display: flex; align-items: center; gap: 7px; font-family: var(--f-mono); font-weight: 500; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; white-space: nowrap; color: var(--blue); padding: 4px 1px; transition: color .15s, opacity .15s; }
.fb-file:hover { color: var(--blue-ink); }
.fb-file:disabled { color: var(--muted); opacity: .55; cursor: default; }
.fb-note.is-settled { grid-template-rows: 1.7fr auto auto 1fr; row-gap: 0; column-gap: 34px; }
.fb-note.is-settled .fb-slot { grid-row: 1 / -1; }
.fb-note.is-settled .fb-head { grid-row: 2; grid-column: 2; }
.fb-note.is-settled .fb-foot { grid-row: 3; min-height: 0; padding-top: 4px; }
.fb-note.is-settled .fb-q { font-size: 18px; padding-top: 0; }
.fb-draft { margin-right: 4px; padding: 4px 7px; border-radius: 6px; background: var(--blue-soft); color: var(--blue); font-family: var(--f-mono); font-weight: 500; font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; }
.dock { position: sticky; bottom: 0; z-index: 9; padding: 14px 0 calc(18px + env(safe-area-inset-bottom, 0px)); background: var(--bg); }
.dock form.composer { max-width: 720px; margin: 0 auto; }

/* ---------- Toast & Options (the review switches; not part of the design) ---------- */
.toast { position: fixed; left: 50%; bottom: calc(22px + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%); background: var(--ink); color: var(--paper); z-index: 40; font-size: 14px; padding: 10px 16px; border-radius: 10px; max-width: calc(100% - 32px); }
.opts { position: fixed; left: max(12px, env(safe-area-inset-left, 0px)); bottom: calc(12px + env(safe-area-inset-bottom, 0px)); z-index: 30; font-size: 13px; color: var(--ink); }
.opts-toggle { display: inline-flex; align-items: center; gap: 8px; padding: 8px 13px; border-radius: 999px; background: var(--ink); color: #fff; font-weight: 600; font-size: 13px; box-shadow: 0 8px 20px -10px rgba(22,51,79,.6); } /* taste-skill-ignore: review switches, not part of the design */
.opts-toggle svg { width: 14px; height: 14px; }
.opts-panel { position: absolute; left: 0; bottom: calc(100% + 8px); width: min(340px, calc(100vw - 24px)); max-height: min(74vh, 640px); overflow: auto; overscroll-behavior: contain; background: var(--surface); border-radius: 14px; padding: 4px 16px 14px; box-shadow: 0 0 0 1px rgba(22,51,79,.1), 0 24px 48px -24px rgba(22,51,79,.55); } /* taste-skill-ignore: review switches, a floating panel */
.opts-title { font-weight: 650; font-size: 15px; padding-top: 12px; }
.opts-title span { font-weight: 500; color: var(--muted); font-size: 13px; margin-left: 4px; }
.opts-panel .opts-h { font-size: 12.5px; font-weight: 650; color: var(--muted); padding: 14px 0 0; }
.opts-panel fieldset { border: 0; padding: 10px 0 2px; margin: 0; min-width: 0; }
.opts-panel legend { font-weight: 600; font-size: 13px; padding: 0; margin-bottom: 6px; }
.seg { display: flex; flex-wrap: wrap; gap: 4px; }
.seg button { padding: 5px 9px; border-radius: 7px; font-size: 12.5px; line-height: 1.3; color: var(--muted); background: #F1F4F7; text-align: left; }
.seg button:hover { color: var(--ink); }
.seg button[aria-pressed="true"] { color: var(--ink); background: var(--gold-soft); }
.opts-panel .why { font-size: 12px; color: var(--muted); margin-top: 12px; line-height: 1.45; }

@container page (max-width: 760px) {
  #hero { --hero-size: 34px; text-align: left; }
  .landing { padding-top: 10px; }
  .ask-wrap { margin-top: 30px; }
  .thread { padding-top: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-delay: 0ms !important; transition: none !important; }
  .dance .foot { opacity: .9; } .dance text { opacity: 1; }
}

/* ================= Round 9 · Powder ================= */
:root { --sky-ink: #16334F; --hl-yellow: rgba(255,209,0,.26); --hl-blue: rgba(165,195,222,.5); }

/* The highlighter under "this winter": pale, one of three. */
.hl::after { height: .3em; bottom: .07em; }
[data-hl="yellow"] .hl::after { background: var(--hl-yellow); }
[data-hl="blue"] .hl::after { background: var(--hl-blue); }
/* Round 43: Snowbank, his pick (Anthony: "I love Snowbank"): the frost toned down to nearly one blue,
   the sky's own a shade deeper, warmed at the very start. */
[data-hl="frost"] .hl::after { background: linear-gradient(90deg, rgba(240,226,180,.34), rgba(180,205,230,.44) 30%, rgba(168,198,226,.44)); } /* taste-skill-ignore: the Snowbank highlighter, Anthony's fixed pick */

/* Royce Hall, soft and low; its foot fades into the page instead of ending on a line. */
.landmark .royce { opacity: .9; filter: saturate(.72); -webkit-mask-image: linear-gradient(#000 62%, transparent 100%); mask-image: linear-gradient(#000 62%, transparent 100%); } /* taste-skill-ignore: fade of an unused landmark layer */
.landmark .bear { filter: saturate(.8); -webkit-mask-image: linear-gradient(#000 80%, transparent 100%); mask-image: linear-gradient(#000 80%, transparent 100%); } /* taste-skill-ignore: fade of an unused landmark layer */

/* The lines, as in Slips: ink that darkens, a dot that turns gold, the label highlighted, all at once. */
.leaders .ink { fill: rgba(22,51,79,.55); transition: fill .15s; }
.leaders .trace { display: none; fill: none; stroke-linecap: round; transition: stroke .15s, stroke-width .15s; }
.leaders .end { fill: var(--surface); stroke: var(--ink); stroke-width: 1.1; transition: r .25s var(--ease), fill .15s; }
.leaders .ring { fill: none; stroke: var(--gold); stroke-width: 1.6; opacity: 0; transform-box: fill-box; transform-origin: center; scale: .4; transition: opacity .2s, scale .35s var(--ease); }
.leaders g.on .ink { fill: var(--ink); }
.leaders g.on .end { fill: var(--gold); r: 6px; }
[data-dot="ring"] .leaders g.on .end { r: 4px; }
[data-dot="ring"] .leaders g.on .ring { opacity: 1; scale: 1.25; }
[data-line="fine"] .leaders .ink, [data-line="pencil"] .leaders .ink { display: none; }
[data-line="fine"] .leaders .trace { display: block; stroke: rgba(22,51,79,.5); stroke-width: 1.15; }
[data-line="fine"] .leaders g.on .trace { stroke: var(--ink); stroke-width: 1.6; }
[data-line="pencil"] .leaders .trace { display: block; stroke: rgba(70,82,94,.62); stroke-width: 1; stroke-dasharray: 5 1.2 9 1.6; }
[data-line="pencil"] .leaders g.on .trace { stroke: #2C3B49; stroke-width: 1.35; }
.leaders g.soon { opacity: .42; }
.label b { transition: background-size .18s var(--ease); } /* taste-skill-ignore: a flat highlighter stroke, not a gradient fill */

/* ---------- Search: the Ask bar's one tab (Round 12) ---------- */
/* Set as Round 9 set its tabs: the word on the page, no chip or edge around it, and its Beta tag
   beside it. Its padding hangs outside the column, so "Search" starts on the line where Ask's own
   text starts; pointed at, it takes a pale wash in its tag's colour. Round 15: the tag is quieter
   (lighter, smaller, a paler wash) and brown on every device (Anthony's pick over yellow); Round 13
   had crust on a desktop and ice blue on a phone. */
.modes { display: flex; margin: 0 0 10px -12px; }
.mode { --wash: var(--crust-soft); display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px; border-radius: 999px; font-size: 14.5px; font-weight: 600; color: var(--muted); text-decoration: none; transition: background-color .2s, color .2s; }
.mode .bb-name { font-family: var(--f-display); font-weight: 700; letter-spacing: -.01em; }
.mode:hover, .mode:focus-visible { background: var(--wash); color: var(--crust-ink); }
.mode:focus-visible { border-radius: 999px; }
.bb-tag { font: 500 11px/1 var(--f-body); letter-spacing: .01em; padding: 3px 6px; border-radius: 999px; white-space: nowrap; background: var(--tag-bg); color: var(--tag-ink); transition: background-color .2s; }
.mode:hover .bb-tag { background: var(--tag-hover); }
[data-beta="brown"] .mode { --wash: rgba(176,112,48,.1); --tag-bg: rgba(176,112,48,.11); --tag-hover: rgba(176,112,48,.2); --tag-ink: #875A31; }

/* ---------- Banana Bread ---------- */
/* The writing line sits in the header beside the brand, as a search page keeps its box. Nothing
   else up there: the brand is the way back (Round 17, Anthony: "The logo icon itself should serve
   that purpose"; Round 16's arrow is gone). */
:is(#bread, .app) .bar { display: grid; grid-template-columns: 1fr minmax(0, 660px) 1fr; align-items: center; column-gap: 36px; }
:is(#bread, .app) .bar .brand { grid-column: 1; grid-row: 1; justify-self: start; }
:is(#bread, .app) .bar form { grid-column: 2; grid-row: 1; }
/* The way home, on Search and About: the banana nods toward it under the pointer. */
.brand svg { transition: transform .45s var(--ease); }
/* Round 41: About's tilt on every page's banana (Anthony: "to indicate that it's clickable"). */
.brand:hover svg, .brand:focus-visible svg { transform: rotate(-34deg) translateX(-2px); }
.bb { max-width: 900px; margin: 0 auto; padding-bottom: 140px; }
.bb-search { display: flex; align-items: flex-end; padding: 10px 0 8px; border-bottom: 2px solid rgba(22,51,79,.3); transition: border-color .2s; }
.bb-search:focus-within { border-color: var(--gold); }
/* The line grows: a long search, typed or taken from the ghost, wraps onto the lines below instead
   of running under the button. The text and the ghost share one cell, so the taller sets its height. */
.bb-field { position: relative; flex: 1; min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; column-gap: 12px; }
.bb-field textarea { grid-area: 1 / 1; display: block; width: 100%; min-width: 0; border: 0; outline: none; resize: none; overflow: hidden; background: transparent; font: inherit; font-size: 17.5px; line-height: 28px; color: var(--ink); padding: 0; margin: 0; height: 28px; }
.bb-field textarea:focus-visible { outline: none; }
.bb-field textarea::placeholder { color: var(--muted); opacity: .8; }
.bb-field:has(.bb-ghost:not(:empty)) textarea::placeholder { color: transparent; }
/* The button: a small ink dot with an arrow, sitting at the end of the line's last row with its
   middle on the middle of the text (the row is 28px; the button 26px, lifted 1px). */
.line-send { grid-column: 2; align-self: end; flex: none; display: grid; place-items: center; width: 26px; height: 26px; margin-bottom: 1px; border-radius: 50%; background: var(--ink); color: #fff; transition: background-color .2s, transform .2s var(--ease); }
.line-send svg { width: 14px; height: 14px; }
.line-send:hover { background: var(--blue-ink); }
.line-send:active { transform: scale(.92); }
.line-send:focus-visible { border-radius: 50%; }
/* The small controls reach 44px under a thumb without being drawn any bigger. */
.line-send, .mode, .send { position: relative; }
.line-send::after { content: ""; position: absolute; inset: -9px; border-radius: 50%; }
.mode::after { content: ""; position: absolute; inset: -6px 0; }
.send::after { content: ""; position: absolute; inset: -7px -8px; }
#bread[data-state="start"] .bb-results { display: none; }
#bread.arriving .bb-search { visibility: hidden; }
#bread.arriving .bar > :not(form) { opacity: 0; }

/* ---- The ghost in the line: the opener, then suggestions rolling over it ---- */
.bb-ghost { grid-area: 1 / 1; position: relative; z-index: 1; align-self: start; display: block; font-size: 17.5px; line-height: 28px; color: var(--muted); pointer-events: none; }
.bb-ghost:empty { display: none; }
.bb-ghost .gw { position: relative; display: grid; min-width: 0; }
.bb-ghost .gw.roll { overflow: hidden; }
.bb-ghost .g { grid-area: 1 / 1; opacity: .85; }
.bb-ghost .g span { display: inline-block; white-space: pre; }
.bb-ghost .g.sug { color: #7D8C9C; opacity: 1; pointer-events: none; cursor: pointer; }
.bb-field:focus-within .bb-ghost .g.sug { pointer-events: auto; }
.bb-ghost .g.sug:hover { color: var(--ink); }
.bb-ghost.taken .g.sug, .bb-ghost.taken .g.sug span { color: var(--ink); transition: color .18s; }
@keyframes blink { 50% { opacity: 0; } }

/* ---- Results: Round 1's folded cards, one number column on the right (Round 13) ---- */
:is(#bread, .app) { --nc: 84px; }
.bb-results { margin-top: 26px; }
.bb-cols { position: relative; z-index: 3; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; gap: 14px; padding: 0 18px 6px; }
.bb-count { font-size: 14px; color: var(--muted); }
/* The column's header is a menu button: its own small muted words with a chevron, a touch area of
   44px. The menu drops from it, right-aligned, one card with a soft shadow: the rating and A%, then
   a rule and "Hide numbers"; the one showing is ticked. The same on a phone. */
/* The column's header (Round 14): one button, one click to the next of Rating, A% and Hidden. Its
   word ends exactly where the numbers end (the header row and the cards share their right
   padding, and the button's own padding is taken back by a negative margin), with its switch mark
   before the word, as a numeric column's sort mark goes. */
.col-btn { position: relative; justify-self: end; display: inline-flex; align-items: center; gap: 5px; margin-right: -6px; padding: 3px 6px; border-radius: 6px; font-size: 12.5px; font-weight: 500; line-height: 18px; color: var(--muted); transition: color .2s, background-color .2s; }
.col-btn::after { content: ""; position: absolute; inset: -13px -6px; }
.col-btn svg { width: 13px; height: 13px; flex: none; }
.col-btn .col-name { display: inline-block; }
.col-btn:hover { color: var(--ink); background: rgba(127,150,175,.12); }
/* A first search waits with the chat's snowflake where the first row will land. */
.bb-wait { display: none; padding: 14px 0 0 16px; }
:is(#bread, .app).waiting .bb-wait { display: block; }
:is(#bread, .app).waiting .bb-cols { visibility: hidden; }
.bb-list { list-style: none; padding: 0; display: grid; gap: 8px; transition: opacity .3s; }
.card { background: var(--surface); border-radius: 10px; box-shadow: inset 0 0 0 1px #DEE5EC; transition: box-shadow .2s; } /* taste-skill-ignore: results are an app screen: a quiet 1px edge */
.card:hover { box-shadow: inset 0 0 0 1px #B7C6D4; } /* taste-skill-ignore: an app-screen card's 1px edge, no shadow */
.card summary { list-style: none; cursor: pointer; display: grid; grid-template-columns: 14px auto minmax(0, 1fr) var(--nc); align-items: center; gap: 4px 14px; padding: 14px 18px 14px 16px; }
/* One number at a time: the column's menu sets #bread[data-col] to rating, arate or none. */
:is(#bread, .app)[data-col="rating"] .num.na, :is(#bread, .app)[data-col="arate"] .num.nr, :is(#bread, .app)[data-col="none"] .num { display: none; }
:is(#bread, .app)[data-col="none"] .card summary { grid-template-columns: 14px auto minmax(0, 1fr); }
.card summary::-webkit-details-marker { display: none; }
.card summary::before { content: ""; width: 7px; height: 7px; border-right: 1.6px solid var(--muted); border-bottom: 1.6px solid var(--muted); transform: rotate(-45deg); transition: transform .25s var(--ease); }
/* Round 49 (Anthony's screenshot of About's demo: the numbers a column in from the edge, the rank where
   the chevron goes): each part of a row has its own column, so a row without its chevron drawn keeps
   the number at the right edge instead of everything sliding one column left. */
.card summary::before { grid-column: 1; } .card summary > .rank { grid-column: 2; } .card summary > .head { grid-column: 3; } .card summary > .num { grid-column: 4; }
.card[open] summary::before { transform: rotate(45deg) translate(-2px, -2px); }
.card .rank { min-width: 1.4em; font-size: 13.5px; font-weight: 500; color: var(--muted); font-variant-numeric: tabular-nums; text-align: right; }
.card .head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; min-width: 0; }
.card .top { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; min-width: 0; }
.card .code { font-family: "Spline Sans Mono", ui-monospace, monospace; font-weight: 500; font-size: 12.5px; letter-spacing: .02em; color: var(--blue-ink); white-space: nowrap; } /* taste-skill-ignore: course codes are IDs; the app-screen rules set IDs in mono */
.card .title { flex-basis: 100%; font: 600 17px/1.3 var(--f-display); letter-spacing: -.01em; color: var(--ink); }
.move { font-size: 12px; font-weight: 600; padding: 1px 8px; border-radius: 999px; }
.move.up { background: rgba(94,138,58,.14); color: #3F6A22; }
.move.new { background: var(--gold-soft); color: var(--ink); }
/* "3 sections": a course with more than one, said once on its row, quietly. */
.secs { font-size: 12.5px; font-weight: 500; color: var(--muted); white-space: nowrap; }

/* The number: a cell centred on the row as a block, the way the title is; on a desktop the rating's
   review count sits under it. Each number's look is a review switch of its own, Anthony's picks the
   defaults: the rating's number in its colour (a touch heavier, no dot), A% in ink with a small dot
   in its true colour, centred on the height of the digits. Either can take the other's look. */
.num { display: grid; justify-items: end; align-content: center; font-variant-numeric: tabular-nums; }
.num b { font: 600 15px/20px var(--f-body); color: var(--ink); white-space: nowrap; }
.num .mk { display: inline-block; width: 6px; height: 6px; margin-right: 6px; border-radius: 50%; background: var(--c); vertical-align: calc(.35em - 3px); vertical-align: calc(.5cap - 3px); }
[data-rstyle="color"] .num.nr .mk, [data-astyle="color"] .num.na .mk { display: none; }
[data-rstyle="color"] .num.nr b, [data-astyle="color"] .num.na b { color: var(--cd); font-weight: 650; }
.num small { font-size: 11.5px; line-height: 15px; color: var(--muted); white-space: nowrap; }
.num.none b { font-size: 12.5px; font-weight: 500; color: var(--muted); letter-spacing: .02em; }
/* The opened card: its lines (one or more lists of them) in one column. */
.card .body { display: grid; gap: 7px; padding: 0 18px 16px 44px; }
.fields { display: grid; gap: 7px; font-size: 15.5px; line-height: 1.55; max-width: 62ch; }
.fields div { display: block; }
.fields .t { white-space: nowrap; }
.fields .lec { font-size: 13px; color: var(--muted); }
.fields dt { display: inline; font-weight: 600; color: var(--muted); }
.fields dt::after { content: ": "; }
.fields dd { display: inline; margin: 0; color: var(--ink); }
.fields .ge { color: var(--ink); background: linear-gradient(rgba(255,209,0,.34), rgba(255,209,0,.34)) 0 88% / 100% 42% no-repeat; } /* taste-skill-ignore: a flat highlighter stroke */
:is(#bread, .app).baking .bb-list { opacity: .3; }
/* Round 44: Sky, his pick (Anthony: "I love sky"): a tint of UCLA blue, faint at the top-left and
   gone by the bottom-right, so the sky and the paper come through. */
.q p { background: linear-gradient(150deg, rgba(39,116,174,.06), rgba(39,116,174,.012)); } /* taste-skill-ignore: his Sky bubble */

/* "Bake your own": the Ask bar, lifted off the landing on its way up. */
.floatbar { position: fixed; z-index: 60; display: flex; align-items: flex-end; justify-content: space-between; gap: 14px; padding-bottom: 8px; border-bottom: 2px solid rgba(22,51,79,.3); pointer-events: none; transform-origin: 0 0; }
.floatbar .fb-ph, .floatbar .fb-send { display: inline-grid; }
.floatbar .fa, .floatbar .fb { grid-area: 1 / 1; transition: opacity .3s; }
.floatbar .fb { opacity: 0; }
.floatbar.to .fa { opacity: 0; } .floatbar.to .fb { opacity: 1; }
.floatbar .fb-ph { font-size: 17px; line-height: 26px; color: var(--muted); }
.floatbar .fb-ph.typed { min-width: 0; color: var(--ink); }
.floatbar .fb-ph.typed .fa { opacity: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.floatbar .fb-send { grid-template-columns: auto auto; align-items: center; column-gap: 7px; color: var(--blue); font-weight: 600; font-size: 15px; padding: 4px 0 2px; }
.floatbar .fb-send .fa, .floatbar .fb-send .fb { grid-area: 1 / 1; justify-self: end; }
.floatbar .fb-send .fa { display: inline-flex; align-items: center; gap: 7px; }
.floatbar .fb-send .fa svg { width: 13px; height: 13px; }
.floatbar .fb-btn { display: grid; place-items: center; width: 26px; height: 26px; margin-bottom: 1px; border-radius: 50%; background: var(--ink); color: #fff; }
.floatbar .fb-btn svg { width: 14px; height: 14px; }

@container page (max-width: 760px) {
  :is(#bread, .app) .bar { grid-template-columns: minmax(0, 1fr); grid-template-areas: "brand" "line"; row-gap: 4px; }
  :is(#bread, .app) .bar .brand { grid-area: brand; } :is(#bread, .app) .bar form { grid-area: line; }
  /* Round 21 (Anthony: the banana and "Finder" sat too high, cut off by the screen): the brand gets
     the conversation's own band, 66px with the brand in its middle, and the line goes under it. */
  #bread .bar { grid-template-rows: 66px auto; row-gap: 0; }
  #bread .bar .brand { align-self: center; }
  .bb-field textarea, .bb-ghost { font-size: 17px; }
  .num b { font-size: 14.5px; }
  .num small { display: none; }
  .card summary::before, .card .rank { display: none; }
  .card .body { padding: 0 14px 14px 14px; }
  /* A phone (Round 13): the same one column as a desktop, the number centred on the row beside the
     title; the review count waits in the opened card. */
  .bb-cols { padding: 0 14px 6px; }
  .card summary { grid-template-columns: minmax(0, 1fr) auto; gap: 4px 14px; padding: 12px 14px; }
  .card summary > .head { grid-column: 1; } .card summary > .num { grid-column: 2; }   /* Round 49: a phone's two columns */
  :is(#bread, .app)[data-col="none"] .card summary { grid-template-columns: minmax(0, 1fr); }
  .bb-wait { padding: 12px 0 0 14px; }
}

/* Round 9b: Slips' ripeness tags back under the labels, and "Bruinwalk" tinted at rest. */
.label .stat { font-family: "Spline Sans Mono", ui-monospace, monospace; font-weight: 500; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; padding: 3px 7px; border-radius: 4px; width: max-content; white-space: nowrap; margin-top: 4px; color: var(--ink); } /* taste-skill-ignore: the ripeness tags, Anthony's Round 9b pick */
.label .stat.ripe { background: var(--gold-soft); }
.label .stat.turning { background: rgba(194,198,76,.30); }
/* Unripe (Round 12): the unripe banana's green wash, its word a shade lighter, as its label is. */
.label .stat.unripe { background: rgba(127,163,92,.18); color: #536B57; }
.plate.phone .label .stat { font-size: 10.5px; padding: 2px 6px; }
/* Unripe shows on a desktop only (Anthony, Round 15). */
.plate.phone .label .stat.unripe { display: none; }
/* UCLA Grade Distributions on a phone, set flush left. */
.plate.phone .label.end-align.flush { text-align: left; justify-items: start; }
.plate.phone .label.end-align.flush b { background-position: left 88%; }
/* "UCLA": plain ink at rest; pointed at, its letters turn a quiet blue (between the ink and UCLA
   blue) and lift a hair, one after another. */
:root { --uc-blue: #24598A; }
/* Round 42 (Anthony: "should return to what it was previously two rounds ago… Just keep the color
   change for UCLA"): Round 39's wave, letter by letter, in each name's own ink; only "UCLA" turns blue. */
.label .nm .wd { white-space: nowrap; }
.label .nm .ch { display: inline-block; transition: color .2s, transform .3s var(--ease); transition-delay: calc(var(--i) * 14ms); }
.label.on .nm .ch { transform: translateY(-1.5px); }
.label[data-k="2"].on .nm .wd:first-child .ch { color: var(--uc-blue); }
/* Round 45, Blue tide (Anthony: "only UCLA rising before Grade Distributions looks a bit strange"):
   the whole name waves, and the blue runs out of UCLA with the wave, each letter of "Grade
   Distributions" turning blue as it lifts and back to ink as it settles; UCLA keeps it. */
.label[data-k="2"].on .nm .wd:not(:first-child) .ch { animation: uc-tide .75s var(--ease) both; animation-delay: calc(var(--i) * 14ms + 40ms); }
@keyframes uc-tide { 0% { color: var(--label-ink); } 30% { color: var(--uc-blue); } 100% { color: var(--label-ink); } }

/* The grey line under each label. "orig" is Round 9's; the others keep its face and grey and only
   change the sizes, weights and spacing between name, line and tag. */
.label { gap: 0; }
.label .stat { margin-top: 6px; } /* taste-skill-ignore: the ripeness tags, Anthony's Round 9b pick */
[data-sub="orig"] .label { gap: 2px; } [data-sub="orig"] .label .stat { margin-top: 4px; }
[data-sub="orig"] .label small { font-size: 14px; line-height: 1.4; color: var(--muted); }
[data-sub="snug"] .label b { line-height: 1.22; }
[data-sub="snug"] .label small { font-size: 14px; line-height: 1.3; color: #566B80; margin-top: 2px; }
[data-sub="snug"] .label .stat { margin-top: 10px; }
[data-sub="even"] .label b { line-height: 1.22; }
[data-sub="even"] .label small { font-size: 15px; line-height: 1.3; color: #67798B; letter-spacing: -.004em; margin-top: 1px; }
[data-sub="even"] .label .stat { margin-top: 9px; }
[data-sub="weight"] .label b { font-size: 17.5px; font-weight: 650; letter-spacing: -.012em; line-height: 1.22; }
[data-sub="weight"] .label small { font-size: 14px; line-height: 1.35; font-weight: 500; color: #6A7D90; margin-top: 2px; }
[data-sub="weight"] .label .stat { margin-top: 9px; }
.plate.phone .label small { font-size: 13px; }
[data-sub="even"] .plate.phone .label small { font-size: 14px; }
[data-sub="weight"] .plate.phone .label b { font-size: 16px; }
.plate.phone .label .stat { margin-top: 6px; }

/* ---------- About: the walk (Round 9g; Round 18 times it by --step, a print landing each step) ---------- */
/* A print lands every --step (400ms). */
.dance { --step: 400ms; display: block; margin: clamp(8px, 2.5vh, 26px) 0 0; cursor: pointer; }
.dance svg { display: block; width: 100%; height: auto; overflow: visible; color: #6F849A; }
/* The trail between prints draws itself as each step lands. */
.dance .seg { fill: none; stroke: rgba(22,51,79,.34); stroke-width: 1.4; stroke-linecap: round; stroke-dasharray: .006 .014; opacity: 0; }
.dance .step { opacity: 0; transform-box: fill-box; transform-origin: center; }
.dance .foot { fill: #3B536D; transform-box: fill-box; transform-origin: center; }
.dance text { font-family: "Spline Sans Mono", ui-monospace, monospace; font-weight: 500; font-size: 21px; fill: var(--blue-ink); clip-path: inset(0 100% 0 0); } /* taste-skill-ignore: the footsteps' labels as first drawn, Anthony's pick */
.dance text .subj { fill: var(--ink); }
.dance.go .step { animation: land .55s calc(var(--i) * var(--step) + var(--step) - 330ms) cubic-bezier(.3,1.5,.5,1) forwards; }
.dance.go .foot .heel { animation: heel .5s calc(var(--i) * var(--step) + var(--step) - 330ms) ease-out backwards; }
.dance.go .foot .sole { animation: heel .5s calc(var(--i) * var(--step) + var(--step) - 240ms) ease-out backwards; }
.dance.go .seg { animation: segin .4s calc(var(--i) * var(--step) + var(--step) - 650ms) ease-out forwards; }
.dance.go text { animation: type .5s calc(var(--i) * var(--step) + var(--step) - 190ms) steps(8, end) forwards; }
/* Once it has walked, it keeps a little life: each print shifts its weight now and then. */
.dance.go .foot { animation: sway 3.2s calc(var(--i) * var(--step) + 2.6s + var(--i) * .27s) ease-in-out infinite; }
@keyframes land { 0% { opacity: 0; translate: 0 -14px; scale: 1.25; } 60% { opacity: 1; translate: 0 1px; scale: .94; } 100% { opacity: 1; translate: 0 0; scale: 1; } }
@keyframes heel { from { opacity: 0; } }
@keyframes segin { to { opacity: 1; } }
@keyframes type { to { clip-path: inset(0 0 0 0); } }
@keyframes sway { 0%, 100% { translate: 0 0; } 50% { translate: 0 -1.5px; } }
/* Pressed into snow: each print is a dent with a bright rim, and a little powder jumps as it lands. */
.dance[data-v="snow"] .foot { fill: #C3D2E0; stroke: #91A8BF; stroke-width: 1.1; filter: drop-shadow(0 -1px 0 #fff) drop-shadow(0 1.5px 1.5px rgba(22,51,79,.18)); } /* taste-skill-ignore: a pressed print's rim, part of the drawing */
.dance .puff circle { fill: #fff; stroke: rgba(80,112,150,.5); stroke-width: .7; opacity: 0; }
.dance.go .puff circle { animation: puff .8s calc(var(--i) * var(--step) + var(--step) - 250ms) cubic-bezier(.2,.7,.3,1) forwards; }
@keyframes puff { 0% { opacity: 0; transform: rotate(var(--a)) translateX(10px); } 20% { opacity: 1; } 100% { opacity: 0; transform: rotate(var(--a)) translateX(30px) translateY(-6px); } }
/* A dance chart: feet land turned and swivel to rest; curved arrows lead from step to step. */
.dance .arc { fill: none; stroke: rgba(22,51,79,.45); stroke-width: 1.3; stroke-dasharray: 1; stroke-dashoffset: 1; marker-end: url(#ah); opacity: 0; }
.dance.go .arc { animation: drawarc .5s calc(var(--i) * var(--step) + var(--step) - 750ms) ease-out forwards; }
@keyframes drawarc { 0% { opacity: 1; } 100% { opacity: 1; stroke-dashoffset: 0; } }
.dance[data-v="dance"].go .foot { animation: swivel .6s calc(var(--i) * var(--step) + var(--step) - 330ms) cubic-bezier(.3,1.4,.5,1) backwards; }
@keyframes swivel { from { rotate: var(--turn); } }
/* Returned to after it was told (scrolled back, or a resize): the walk as it ended. */
.dance.now :is(.step, .heel, .sole, .seg, text, .arc, .puff circle) { animation-duration: 1ms !important; animation-delay: 0s !important; }

/* ---------- About (Round 19: Focus, a scene at a time, moved on by a small swipe) ---------- */
/* Anthony's Round 20 script, told the Focus way on a phone and a desktop alike: the dance; the
   scramble, each tab its own line, as the title goes, and "Looking for someone in CS who actually
   teaches." word by word like them; why he made this, "I made this to show how information, when
   presented clearly, can make quarters go smoother." at the left and "And even may change a life." at
   the right; Search on a phone, his question still being typed, sent and answered, and the screen
   scrolled on past it; "The best professors are hard to come by. But now", then "But now" alone, which
   rises away in specks; "it's all in your hands." alone; his portrait, small, above "Created by".
   Read plainly (reduced motion, or no GSAP) it is one page, scene under scene. In story mode
   (.story-on, winter20.js Story) About is one screen that does not scroll: each scene fills it and
   comes and goes in GSAP, and a small swipe, scroll or arrow key moves the story on. This file only
   sets each scene as it rests. */
.about { --f-about: var(--f-display); --tx: clamp(23px, 2.3vw, 31px); position: relative; max-width: 1080px; margin: 0 auto; }
.sc { position: relative; padding-block: clamp(30px, 6vh, 64px); }
.opening { font-family: var(--f-about); font-weight: 650; font-size: clamp(36px, 4.6vw, 60px); line-height: 1.02; letter-spacing: -.03em; text-wrap: balance; }
.text { font-family: var(--f-about); font-weight: 450; font-size: var(--tx); line-height: 1.3; letter-spacing: -.012em; text-wrap: pretty; }
.about .w, .about .wi { display: inline-block; }
.scramble { margin-top: clamp(16px, 3vh, 32px); max-width: 30rem; }
.scramble .ln { display: block; margin-bottom: .3em; }
.made { max-width: 40rem; }
.made .mline { display: block; }
.made .m2 { margin-top: 1em; text-align: right; }
.best { max-width: 40rem; }
/* "But now" together, never split across lines. */
.but { display: inline-block; white-space: nowrap; }
.hands { font-family: var(--f-about); font-weight: 500; font-size: clamp(30px, 3.6vw, 52px); line-height: 1.15; letter-spacing: -.022em; }
/* The highlighter, ice (Round 15), in one stroke across the words. */
.hands .ice { --hl: rgba(160,192,222,.5); background: linear-gradient(var(--hl), var(--hl)) 0 88% / 100% 36% no-repeat; -webkit-box-decoration-break: clone; box-decoration-break: clone; } /* taste-skill-ignore: a flat highlighter stroke, not a gradient fill */
/* The sign-off: his portrait above "Created by" (Round 17), small (Round 19: Round 18's larger print
   asked less to be opened), a little more room under it (Round 20), and the name with the email on
   one line (Round 14), no cursive and no "Contact". The print is cut to its 4:5 frame at twice its
   size, so it is drawn sharp as it comes in; opened, it swaps to the full cut (winter20.js Photo). */
.sign { display: grid; grid-template-columns: auto auto; grid-template-areas: "pic pic" "by reach"; justify-content: center; align-items: last baseline; column-gap: 22px; }
.portrait { --pw: clamp(150px, 15vw, 224px); grid-area: pic; justify-self: center; position: relative; margin: 0 0 clamp(28px, 4.6vh, 42px); }
.pic { display: block; width: var(--pw); padding: 8px; border-radius: 1px; background: var(--surface); box-shadow: 0 1px 2px rgba(22,51,79,.12), 0 26px 44px -30px rgba(22,51,79,.55); cursor: zoom-in; transform-origin: 50% 50%; } /* taste-skill-ignore: his photograph as a mounted print, Anthony's pick */
.pic[aria-expanded="true"] { cursor: zoom-out; position: relative; z-index: 3; }
.pic img { width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover; object-position: 50% 42%; }
.pic:focus-visible { outline-offset: 4px; border-radius: 2px; }
/* Where it was taken, as Anthony's Round 14 screenshot has it: in the reading face's italic, muted,
   down the print's right edge just clear of it, ending at its bottom corner, the letters' feet towards
   the photograph. Round 21 (Anthony: "much smaller, in scale with my portrait, but still readable"):
   Round 14's proportion, 13.5px beside a 300px print, so .045 of the print's width (its mount
   included, as --pw is), and its gap the same way; never under 9px, the least that still reads, so
   on a phone, whose print is 150px, it is 9px where the proportion alone would give 6.75, and 9.7px
   beside a 216px print on a 1440 screen. Opened, it rides and grows with the print, to Round 14's
   13.5px at most (winter21.js Photo). */
.place { position: absolute; left: calc(100% + 4px); bottom: 0; z-index: 3; writing-mode: vertical-rl; font-family: var(--f-body); font-style: italic; font-weight: 400; font-size: max(9px, calc(var(--pw) * .045)); line-height: 1.4; letter-spacing: .01em; color: var(--muted); white-space: nowrap; pointer-events: none; }
.sign .by { grid-area: by; text-align: left; } .sign .reach { grid-area: reach; }
.sign h2 { font-family: "Spline Sans Mono", ui-monospace, monospace; font-weight: 500; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin-bottom: 4px; } /* taste-skill-ignore: Round 9e's sign-off labels, Anthony's pick */
.sign .name { font-family: var(--f-display); font-weight: 600; font-size: 22px; letter-spacing: -.01em; }
.sign .name, .sign a { display: inline-block; line-height: 30px; }
.sign a { color: var(--blue-ink); text-decoration-style: dotted; text-underline-offset: 3px; font-size: 16px; }
.sc-end .sign { margin-top: clamp(22px, 4vh, 40px); }
.sc-end { display: flex; flex-direction: column; align-items: center; text-align: center; }

/* ----- Search in the story (Round 26) ----- */
/* Anthony: "removing the phone entirely, making the search and results full-screen and
   interactable, basically like the Results Page." The page is Search's own markup and styles (the
   :is(#bread, .app) rules above), his question in its line where the box would be. In the story it
   covers the whole screen, over the header, its own brand where About's is, and scrolls on its own;
   read plainly, it sits in the page. Its ground is the page's: the sky's pale blue at the top,
   paper below. */
.app { position: relative; color: var(--ink); text-align: left; }
.app .bb { padding-bottom: 120px; }
/* The line holds his question, as the box holds what was typed; nothing can be typed in it. When it is
   shown to the reader it takes focus, as Search's does: its rule gold, a caret blinking at its end. */
.app .line { grid-area: 1 / 1; position: relative; display: block; min-height: 28px; font-size: 17.5px; line-height: 28px; color: var(--ink); overflow-wrap: break-word; cursor: default; }
.app .caret { display: inline-block; width: 2px; height: 21px; margin: 0 -2px -4px 1px; border-radius: 1px; background: var(--ink); opacity: 0; }
.app.focus .caret { animation: blink 1.06s steps(1, end) infinite; opacity: 1; }
.app.focus .bb-search { border-color: var(--gold); }
.app .line-send { cursor: default; }
.app .line-send:hover { background: var(--ink); }
/* The press: a ring spreads from the button as it gives. */
.line-send .ring { position: absolute; inset: 0; border-radius: 50%; box-shadow: 0 0 0 1.5px var(--ink); opacity: 0; pointer-events: none; }
.app .bb-wait .loader { display: inline-block; }
/* LIFESCI 15's description, shortened (Anthony: "shortening the Course Description with a '...' that
   can expand"): two lines, the browser's own "…" at the end of the second; a tap on it, or its
   button for a keyboard, opens it in full. */
.fields .desc.clamp { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; cursor: pointer; }
.fields .desc.clamp:hover dd { color: #2A4866; }
.fields .desc:has(.more:focus-visible) { outline: 2px solid var(--blue); outline-offset: 3px; border-radius: 4px; }
@container page (max-width: 760px) {
  .app .line { font-size: 17px; }
}

/* ----- Story mode: one screen, a scene at a time ----- */
[data-page="about"] canvas.sky { position: fixed; }
html.story-on[data-page="about"], html.story-on[data-page="about"] body { overflow: hidden; overscroll-behavior: none; }
.story-on .ab-stage { position: relative; height: 100svh; display: flex; flex-direction: column; overflow: hidden; }
.story-on .ab-stage > .bar { flex: none; }
.story-on .about { flex: 1; min-height: 0; width: 100%; overflow-x: visible; overflow-y: clip; touch-action: none; }
.story-on .sc { position: absolute; inset: 0; padding: 0; visibility: hidden; }
/* The dance: the title, then the scramble in its place, its first line where the title was, on the
   left; the walk down the right. */
.story-on .sc-first { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); grid-template-rows: minmax(0, 1fr); align-items: center; column-gap: clamp(36px, 6vw, 96px); padding-bottom: 3vh; }
.story-on .words { grid-area: 1 / 1; display: grid; }
.story-on .words > * { grid-area: 1 / 1; align-self: start; }
.story-on .opening { max-width: 9em; }
.story-on .scramble { margin: 0; max-width: 17em; font-size: clamp(26px, 2.6vw, 36px); line-height: 1.22; }
.story-on .scramble .ln { margin-bottom: .28em; }
.story-on .dance { grid-area: 1 / 2; align-self: center; height: min(100%, 600px); margin: 0; }
.story-on .dance svg { width: 100%; height: 100%; }
/* His belief (Round 26), five ways (the bel switch; winter26.js BELS). None of them sits at the left
   as the best professors do (Anthony: "so it doesn't feel repetitive"). One size per way, a little
   larger than the story's other lines, and tighter: the sentence is the story's thesis.
     fold    two blocks either side of a hairline in the middle of the screen, the first set to the
             line's left and the second from its right; on a phone, above and below a short rule.
     split   the first block high at the left, the second low at the right, the screen between them.
     weight  one block above the other in the middle, the first light (300), the second bold (700),
             the same size: the belief, then what it holds.
     focus   one block in the middle.
     light   one block in the middle, at the largest size, edge to edge. */
.made .rule { display: none; }
.story-on .sc-made { display: grid; align-content: center; padding-bottom: 4vh; }
.story-on .made { display: grid; max-width: none; margin: 0; font-weight: 520; letter-spacing: -.026em; }
.story-on .made .mline { max-width: 11em; }
.story-on .made[data-bel="fold"] { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; column-gap: clamp(28px, 3.4vw, 60px); font-size: clamp(30px, 3.1vw, 48px); line-height: 1.12; }
.story-on .made[data-bel="fold"] .m1 { justify-self: end; text-align: right; }
.story-on .made[data-bel="fold"] .m2 { justify-self: start; text-align: left; }
.story-on .made[data-bel="fold"] .rule { display: block; width: 1px; height: max(3.6em, 100%); align-self: center; background: currentColor; opacity: .42; transform-origin: 50% 50%; }
.story-on .sc-made:has(.made:is([data-bel="split"], [data-bel="drift"], [data-bel="thread"], [data-bel="glide"], [data-bel="launch"], [data-bel="peel"], [data-bel="out"], [data-bel="carry"], [data-bel="through"], [data-bel="rest"], [data-bel="accel"])) { align-content: stretch; padding: 7vh 0 11vh; }
.story-on .made:is([data-bel="split"], [data-bel="drift"], [data-bel="thread"], [data-bel="glide"], [data-bel="launch"], [data-bel="peel"], [data-bel="out"], [data-bel="carry"], [data-bel="through"], [data-bel="rest"], [data-bel="accel"]) { grid-template-rows: 1fr 1fr; font-size: clamp(32px, 3.5vw, 54px); line-height: 1.1; }
.story-on .made:is([data-bel="split"], [data-bel="drift"], [data-bel="thread"], [data-bel="glide"], [data-bel="launch"], [data-bel="peel"], [data-bel="out"], [data-bel="carry"], [data-bel="through"], [data-bel="rest"], [data-bel="accel"]) .m1 { align-self: start; justify-self: start; max-width: 10.5em; }
.story-on .made:is([data-bel="split"], [data-bel="drift"], [data-bel="thread"], [data-bel="glide"], [data-bel="launch"], [data-bel="peel"], [data-bel="out"], [data-bel="carry"], [data-bel="through"], [data-bel="rest"], [data-bel="accel"]) .m2 { align-self: end; justify-self: end; text-align: right; max-width: 11em; }
/* Round 28, the experiments on Split. Drift and Thread rest as Split does. Thread's line: a hairline
   of the words' own colour at half strength, drawn over the scene. Stairs: one block the width of the
   page, each phrase its own line, set at its step by winter28.js (x), the second half a little lower
   after "belief". */
.about .thread { display: none; } /* Production: About's line only; the conversation is also .thread */
.story-on .about .thread { display: block; position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; visibility: hidden; }
.thread path { fill: none; stroke: currentColor; stroke-width: 1.1; stroke-linecap: round; opacity: .5; stroke-dasharray: 1; stroke-dashoffset: 1; }
.story-on .made[data-bel="stairs"] { display: block; font-size: clamp(32px, 3.5vw, 54px); line-height: 1.14; }
.story-on .made[data-bel="stairs"] .mline { display: block; max-width: none; }
.story-on .made[data-bel="stairs"] .st { display: block; width: max-content; }
.story-on .made[data-bel="stairs"] .st + .st { margin-top: .1em; }
.story-on .made[data-bel="stairs"] .m2 { margin-top: .5em; }
.story-on .made[data-bel="weight"] { justify-items: center; text-align: center; row-gap: .12em; font-size: clamp(32px, 3.6vw, 56px); line-height: 1.1; }
.story-on .made[data-bel="weight"] .m1 { font-weight: 300; max-width: 15em; letter-spacing: -.02em; }
.story-on .made[data-bel="weight"] .m2 { font-weight: 700; max-width: 13em; letter-spacing: -.032em; }
.story-on .made[data-bel="focus"] { justify-items: center; text-align: center; font-size: clamp(34px, 4.1vw, 62px); line-height: 1.08; font-weight: 560; }
.story-on .made[data-bel="focus"] .m1 { max-width: 13.5em; text-wrap: balance; }
.story-on .made[data-bel="light"] { justify-items: center; text-align: center; font-size: clamp(40px, 5.6vw, 90px); line-height: 1.02; font-weight: 640; letter-spacing: -.036em; }
.story-on .made[data-bel="light"] .m1 { max-width: 13em; text-wrap: balance; }
/* Search, full-screen: the page over the whole screen, the header too, its own brand exactly where
   About's is (the same bar, the same 66px), scrolling on its own. While it rises it is a sheet with
   its corners rounded and a shadow at its edge; at rest the shadow is off the screen. The cue sits
   over it. */
.story-on .app { position: fixed; inset: 0; z-index: 10; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; visibility: hidden;
  padding-inline: var(--gutter) max(16px, env(safe-area-inset-right, 0px)); scrollbar-width: thin; scrollbar-color: rgba(22,51,79,.28) transparent; }
/* Round 27: the page is clear, its ground the story's own (the paper and sky, or the night) with the
   snow behind it, as on Search; About's header stays, and the page's own brand lies over it unseen
   (still the way home). */
.app .bar .brand { opacity: 0; }
.story-on .app .bar { padding-top: env(safe-area-inset-top, 0px); }
/* The specks "But now" rises away in (winter20.js Specks): drawn over the scene, never under a hand. */
.specks { position: absolute; inset: 0; z-index: 2; width: 100%; height: 100%; pointer-events: none; }
.story-on .sc-best { display: grid; align-content: center; padding-bottom: 4vh; }
.story-on .best { justify-self: center; text-align: center; max-width: 15em; font-size: clamp(30px, 3.5vw, 50px); line-height: 1.18; text-wrap: balance; }
.story-on .sc-end { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding-bottom: 2vh; }
/* The cue: more to come. A chevron at the foot of the screen, bobbing, once a scene is waiting. */
.cue { display: none; }
.story-on .cue { display: block; position: absolute; z-index: 11; left: 50%; bottom: max(12px, 2.2vh); width: 30px; height: 30px; margin-left: -15px; color: var(--muted); visibility: hidden; pointer-events: none; }
/* While Search is his, the cue says what to do (Round 26), on a small paper chip so it reads over the
   cards, and the chevron under it says there is more below. */
.cue svg { display: block; }
.cue.say svg { opacity: .62; }
.cue-say { position: absolute; bottom: calc(100% + 6px); left: 50%; translate: -50% 0; white-space: nowrap; font: 500 13.5px/1 var(--f-body); letter-spacing: 0; color: #16334F; padding: 8px 13px; border-radius: 999px; background: rgba(255,255,255,.95); box-shadow: 0 1px 2px rgba(22,51,79,.1), 0 10px 24px -12px rgba(22,51,79,.42); }
.cue-say:empty { display: none; }
html.story-on.app-up:not(.night) .cue { color: #5D7186; }
.cue svg { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

@container page (max-width: 760px) {
  .opening { font-size: 34px; }
  .text { font-size: 22px; }
  .hands { font-size: 30px; }
  .portrait { --pw: 150px; }
  /* Story mode on a phone: one column. The walk, drawn down the screen, steps aside for the
     scramble under the title's place; the phone between its two lines, smaller. */
  .story-on .sc-first { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); align-items: stretch; row-gap: 18px; padding: 2.2vh 0 3vh; }
  .story-on .words { display: contents; }
  .story-on .opening { grid-area: 1 / 1; align-self: start; max-width: none; }
  .story-on .dance { grid-area: 2 / 1; width: 100%; height: 100%; min-height: 0; }
  .story-on .scramble { grid-area: 1 / 1 / 3 / 2; align-self: start; max-width: none; font-size: 25px; line-height: 1.26; }
  /* His belief on a phone: the same five ways in one column. */
  .story-on .made[data-bel="fold"] { grid-template-columns: minmax(0, 1fr); justify-items: center; text-align: center; row-gap: 22px; font-size: 27px; line-height: 1.16; }
  .story-on .made[data-bel="fold"] .m1, .story-on .made[data-bel="fold"] .m2 { justify-self: center; text-align: center; max-width: 11.5em; }
  .story-on .made[data-bel="fold"] .rule { width: 2.4em; height: 1px; }
  .story-on .sc-made:has(.made:is([data-bel="split"], [data-bel="drift"], [data-bel="thread"], [data-bel="glide"], [data-bel="launch"], [data-bel="peel"], [data-bel="out"], [data-bel="carry"], [data-bel="through"], [data-bel="rest"], [data-bel="accel"])) { padding: 4vh 0 12vh; }
  .story-on .made:is([data-bel="split"], [data-bel="drift"], [data-bel="thread"], [data-bel="glide"], [data-bel="launch"], [data-bel="peel"], [data-bel="out"], [data-bel="carry"], [data-bel="through"], [data-bel="rest"], [data-bel="accel"]) { font-size: 29px; line-height: 1.14; }
  .story-on .made:is([data-bel="split"], [data-bel="drift"], [data-bel="thread"], [data-bel="glide"], [data-bel="launch"], [data-bel="peel"], [data-bel="out"], [data-bel="carry"], [data-bel="through"], [data-bel="rest"], [data-bel="accel"]) .m1 { max-width: 9.2em; }
  .story-on .made:is([data-bel="split"], [data-bel="drift"], [data-bel="thread"], [data-bel="glide"], [data-bel="launch"], [data-bel="peel"], [data-bel="out"], [data-bel="carry"], [data-bel="through"], [data-bel="rest"], [data-bel="accel"]) .m2 { max-width: 9.6em; }
  .story-on .made[data-bel="stairs"] { font-size: 29px; line-height: 1.16; }
  .story-on .made[data-bel="weight"] { font-size: 29px; line-height: 1.14; row-gap: .2em; }
  .story-on .made[data-bel="weight"] .m1, .story-on .made[data-bel="weight"] .m2 { max-width: 11.5em; }
  .story-on .made[data-bel="focus"] { font-size: 31px; line-height: 1.12; }
  .story-on .made[data-bel="focus"] .m1 { max-width: 11em; }
  .story-on .made[data-bel="light"] { font-size: 38px; line-height: 1.04; }
  .story-on .made[data-bel="light"] .m1 { max-width: 9.6em; }
  .app .bar { grid-template-rows: 66px auto; row-gap: 0; }
  .app .bar .brand { align-self: center; }
  .story-on .best { font-size: 28px; line-height: 1.24; justify-self: start; max-width: none; }
  .story-on .hands { font-size: 30px; }
}

/* ---------- The highlighter on a label, wintry (Round 11; snow white from Round 12) ---------- */
/* Laid as before, under the lower 38% of the name in one stroke from the label's inner end, but
   now on the name's own inline span, so a name that wraps on a phone gets a stroke under each of
   its lines instead of one under the last. Only the colour is new. ice: a pale powder blue.
   powder: blue into white. glacier: a cooler, deeper ice. snow: white, shading to ice at its foot
   over a cool underside, the way the settled snow is drawn, so it still shows on the paper. */
.label b, .label.on b { background: none; }
.label .nm { --hl: rgba(160,192,222,.58); background: linear-gradient(var(--hl), var(--hl)) left 88% / 0 38% no-repeat; -webkit-box-decoration-break: clone; box-decoration-break: clone; transition: background-size .2s var(--ease); } /* taste-skill-ignore: a flat highlighter stroke, not a gradient fill */
.label.end-align .nm { background-position: right 88%; }
.plate.phone .label.end-align.flush .nm { background-position: left 88%; }
.label.on .nm { background-size: 100% 38%; }
[data-frost="glacier"] .label .nm { --hl: rgba(116,170,214,.42); }
[data-frost="powder"] .label .nm { background-image: linear-gradient(90deg, rgba(140,180,216,.62), rgba(255,255,255,.95)); } /* taste-skill-ignore: a highlighter stroke, blue into white */
[data-frost="powder"] .label.end-align .nm { background-image: linear-gradient(270deg, rgba(140,180,216,.62), rgba(255,255,255,.95)); } /* taste-skill-ignore: the same stroke, from the right */
[data-frost="powder"] .plate.phone .label.end-align.flush .nm { background-image: linear-gradient(90deg, rgba(140,180,216,.62), rgba(255,255,255,.95)); } /* taste-skill-ignore: the same stroke, from the left */
/* Snow white as a finer line (Anthony's picks, Rounds 11 to 13): a stroke just under the baseline,
   white over a cool shade along its foot, the way the settled snow on the bunch is drawn, so white
   still shows on the pale sky. Measured from the foot of the name's box (--d, the font's descent). */
[data-frost="snow"] .label .nm { --d: .24em; --w: .19em; --s: .06em; --up: -.02em; --at: calc(var(--d) + var(--up) - var(--w));
  background-image: linear-gradient(rgba(118,152,190,.62), rgba(118,152,190,.62)), linear-gradient(#FFFFFF 25%, #DCE8F3);
  background-position: left 0 bottom var(--at), left 0 bottom var(--at);
  background-size: 0 var(--s), 0 var(--w); } /* taste-skill-ignore: a snow-white highlighter stroke with its cool underside, as the settled snow is drawn */
[data-frost="snow"] .label.end-align .nm { background-position: right 0 bottom var(--at), right 0 bottom var(--at); }
[data-frost="snow"] .plate.phone .label.end-align.flush .nm { background-position: left 0 bottom var(--at), left 0 bottom var(--at); }
[data-frost="snow"] .label.on .nm { background-size: 100% var(--s), 100% var(--w); }

/* ---------- A course's sections (Round 15; winter15.js Swap) ---------- */
/* One card per section. A card with more than one ends on a row of dots (which card this is) and
   "3 Sections ›", which swaps in the next. During a swap the row is lifted over its neighbours; the
   copies of the card that move are .ghost, and the book's page is .curl. */
.bb-list > li { position: relative; }
.bb-list > li.swapping { z-index: 3; }
.bb-list > li.swapping > .card:not(.ghost) { position: relative; z-index: 1; box-shadow: inset 0 0 0 1px #DEE5EC, 0 calc(var(--lift, 0) * 22px) calc(var(--lift, 0) * 44px) calc(var(--lift, 0) * -14px) rgba(22,51,79,calc(var(--lift, 0) * .34)); } /* taste-skill-ignore: a card in flight casts a soft shadow, gone as it lands */
.card.ghost { position: absolute; left: 0; top: 0; width: 100%; z-index: 0; pointer-events: none; }
.curl { position: absolute; left: 0; top: 0; z-index: 2; pointer-events: none; }
.curl > div { position: absolute; left: 0; top: 0; width: 100%; height: 100%; }
.curl .card.ghost { z-index: auto; }
.c-shade, .c-flap { overflow: hidden; }
.c-flap { position: absolute; inset: 0; transform-origin: 0 0; }
.c-shade i, .c-flap i { position: absolute; left: 0; top: 0; transform-origin: 0 0; }
/* The roll's shadow on the card coming into view, darkest at the fold. */
.c-shade i { background: linear-gradient(90deg, rgba(22,51,79,.24), rgba(22,51,79,.09) 16px, rgba(22,51,79,0) 64px); } /* taste-skill-ignore: the shadow a turning page casts */
/* The page's back: paper, the print faintly through it, light along the roll near the fold. */
.c-back { position: absolute; inset: 0; border-radius: var(--card-r); background: rgba(243,246,250,.945); box-shadow: inset 0 0 0 1px #D9E1E9; } /* taste-skill-ignore: the back of the card, its own 1px edge */
.c-flap i { background: linear-gradient(90deg, rgba(22,51,79,.12), rgba(255,255,255,.7) 9px, rgba(255,255,255,.18) 30px, rgba(255,255,255,0) 70px, rgba(22,51,79,0) 160px, rgba(22,51,79,.06) 480px); } /* taste-skill-ignore: light along a page's roll */

.sec-row { display: flex; align-items: center; justify-content: flex-end; gap: 14px; margin-top: 12px; }
.sec-dots { display: inline-flex; gap: 2px; margin-right: auto; }
.sec-dot { position: relative; width: 16px; height: 16px; border-radius: 50%; }
.sec-dot::before { content: ""; position: absolute; inset: 5px; border-radius: 50%; background: var(--muted); transition: background-color .2s, transform .2s var(--ease); }
.sec-dot[aria-current="true"]::before { background: var(--ink); transform: scale(1.2); }
.sec-dot:hover::before { transform: scale(1.25); }
.sec-dot::after { content: ""; position: absolute; inset: -12px -2px; }
.sec-next { position: relative; display: inline-flex; align-items: center; gap: 4px; margin-right: -6px; padding: 5px 6px 5px 10px; border-radius: 8px; font-size: 14.5px; font-weight: 600; color: var(--blue-ink); transition: background-color .2s; }
.sec-next svg { width: 15px; height: 15px; transition: transform .25s var(--ease); }
.sec-next:hover { background: rgba(39,116,174,.08); }
.sec-next:hover svg { transform: translateX(2px); }
.sec-next::after { content: ""; position: absolute; inset: -8px -4px; }
.sec-next .nx-p { display: none; }
@container page (max-width: 760px) {
  .sec-row { margin-top: 10px; }
  .sec-next .nx-d { display: none; }
  .sec-next .nx-p { display: inline; }
}

/* ---------- At night (Round 26, the night switch; winter26.js Night) ---------- */
/* About's story from his belief on: a blue-black, not a slide's flat black, lit from above as if by
   a streetlamp out of frame and darkest at the foot; it rises from the foot of the screen with a soft
   leading edge, behind the snow. The snow is the same snow seen at night (winter26.js eases its
   canvases' filters): pale, the far flakes fine and dim, bright only in the light from above (a mask
   on the back canvas, --nm, from 1 to .22), the near flakes soft and out of focus. The words are a
   warm white. Search, when it comes, keeps daylight: it is the real page. */
.nightsky { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; visibility: hidden; }
.nightsky .shade { position: absolute; left: 0; right: 0; top: -3%; height: 103%; background: linear-gradient(rgba(7,9,14,0), #07090E 2.9%); } /* Round 27: a clean edge, a few points of feather */ /* taste-skill-ignore: the leading edge of the dark as it rises, not a gradient fill */
.nightsky .glow { position: absolute; inset: 0; opacity: 0; background: radial-gradient(70% 58% at 50% -8%, rgba(132,160,196,.2), rgba(132,160,196,.07) 46%, rgba(132,160,196,0) 74%), radial-gradient(130% 70% at 50% 118%, rgba(0,0,0,.55), rgba(0,0,0,0) 64%); } /* taste-skill-ignore: light from above and the dark at the foot, the night's own depth */
html.nightfall #snow-back { -webkit-mask-image: radial-gradient(118% 92% at 50% -6%, #000 30%, rgba(0,0,0,var(--nm, 1)) 100%); mask-image: radial-gradient(118% 92% at 50% -6%, #000 30%, rgba(0,0,0,var(--nm, 1)) 100%); }
html.night .ab-stage { --ink: #F1EEE8; --muted: #97A2AE; --blue-ink: #A9C8E6; --bar-ink: #F1EEE8; color: var(--ink); }
/* Search at night (Round 27, Anthony: "It should be in dark mode too, I'd love that"): the same page
   over the dark and the snow. Its cards are a blue-black a step up from the night, edged in a faint
   light line (brighter under the pointer), their words the night's warm white and grey, the course
   codes a pale blue; the numbers wear their own colours, the bright ones from the scale; the line's
   rule is a faint light, gold when it takes focus; the button is the warm white with a dark arrow. */
html.night .app { --surface: #0D1219; --tone: #1A222C; scrollbar-color: rgba(255,255,255,.22) transparent; }
html.night .app .card { box-shadow: inset 0 0 0 1px rgba(226,234,244,.1); }
html.night .app .card:hover { box-shadow: inset 0 0 0 1px rgba(226,234,244,.24); }
html.night .app .bb-search { border-bottom-color: rgba(241,238,232,.26); }
html.night .app.focus .bb-search { border-color: var(--gold); }
html.night .app .line-send, html.night .app .line-send:hover { background: #F1EEE8; color: #0B0F15; }
html.night[data-rstyle="color"] .app .num.nr b, html.night[data-astyle="color"] .app .num.na b { color: color-mix(in oklab, var(--c) 70%, #fff); }
html.night .app .num.none b { color: var(--muted); }
html.night .app .fields .ge { background-image: linear-gradient(rgba(255,209,0,.3), rgba(255,209,0,.3)); }
html.night .app .col-btn:hover { background: rgba(226,234,244,.08); }
html.night .app .sec-next:hover { background: rgba(169,200,230,.1); }
html.night ::selection { background: rgba(255,209,0,.42); }
html.night .ab-stage > .bar { transition: color .6s; }
/* The closing line's highlighter at night (Round 27, Anthony: "should be changed so that it fits more
   with the black background"). Any band of colour laid over the dark goes murky (ice went slate, a
   warm band went brown, a fine line read as a link), so at night the stroke is light instead: the
   words are lit one after another, in the stroke's own time, by a soft warm glow, as if caught in the
   lamp (winter27.js sweep). */
html.night .hands .ice { background: none; }
html.night .pic { box-shadow: 0 1px 2px rgba(0,0,0,.5), 0 30px 50px -26px rgba(0,0,0,.95); } /* taste-skill-ignore: his print's shadow, on the dark */

/* ---------- Round 29 ---------- */
/* His question typed in (winter29.js readTl): the caret holds steady while a letter is coming, and
   blinks again once the line is still. */
.app.typing .caret { animation: none; opacity: 1; }

/* An opened card on a phone. Round 29 (Anthony: "The spacing and feel looks amazing on desktop, but
   on mobile it feels off!") gave five ways and Round 30 five more; Round 31 keeps his pick (Anthony:
   "Stack + Pair is also really, really good. Keep those two"), on About's card and Search's results
   alike, since the card is Search's own (Bread). A desktop keeps its lines. Each label is small, over
   its value; the professor, the time and the description one under the next, then Bruinwalk and A%
   side by side, as the two short numbers they are, then the GEs. */
@container page (max-width: 760px) {
  html[data-mcard] .fields { font-size: 15px; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 18px; row-gap: 11px; line-height: 1.45; }
  html[data-mcard] .fields > div { display: grid; align-content: start; gap: 1px; grid-column: 1 / -1; }
  html[data-mcard] .fields dt { display: block; font-size: 12.5px; line-height: 1.45; font-weight: 500; letter-spacing: .012em; }
  html[data-mcard] .fields dt::after { content: none; }
  html[data-mcard] .fields dd { display: block; }
  html[data-mcard] .fields > .f-desc dd { line-height: 1.55; }
  html[data-mcard] .fields > .f-prof { order: 1; }
  html[data-mcard] .fields > .f-meets { order: 2; }
  html[data-mcard] .fields > .f-desc { order: 3; }
  html[data-mcard] .fields > .f-bw { order: 4; grid-column: auto; }
  html[data-mcard] .fields > .f-a { order: 5; grid-column: auto; }
  html[data-mcard] .fields > .f-ge { order: 6; }
}

/* ---------- Round 31 ---------- */
/* The finger (Round 21's, Anthony: "utilize the same grey round circle touch hint from a long while
   ago… tone it down for it to be more subtle"): a soft grey spot where the tap on LIFESCI 15 lands, as
   a screen recording shows one; smaller than Round 21's (30px, not 40) and fainter, a wash with no
   ring. At night it is a pale wash on the dark. */
.app .tap { position: absolute; z-index: 5; left: 0; top: 0; width: 30px; height: 30px; margin: -15px 0 0 -15px; border-radius: 50%; background: rgba(22,51,79,.11); pointer-events: none; visibility: hidden; } /* taste-skill-ignore: a touch indicator, flat */
html.night .app .tap { background: rgba(226,234,244,.13); }

/* His portrait opened is the photograph alone (Anthony: "My portrait shouldn't keep the white border
   surrounding it once expanded. It should just be the photo."): the mount and its shadow fade as it
   rises, while the photograph grows over the mount to its edges (winter31.js Photo), and come back
   as it is put home. */
.pic { transition: background-color .35s ease, box-shadow .45s ease; }
.pic img { transform-origin: 50% 50%; }
.pic[aria-expanded="true"], html.night .pic[aria-expanded="true"] { background-color: transparent; box-shadow: 0 0 0 0 transparent, 0 0 0 0 transparent; }

/* ---------- Round 32, after ---------- */
/* The grey bar along Search's foot (its sideways scroll bar: the round button's ring, spread as it is
   pressed, leaves the page 2px wider than the screen) stays, as Anthony wants it ("Make sure you keep
   that bottom grey bar"); it goes the moment the page starts away into "The best professors…"
   (leaving), so it no longer lingers there. */
.story-on .app.leaving { overflow-x: hidden; }
.cue svg { position: relative; }
/* The arrow over Search (Round 32, after): it rests, and nudges, over whatever card is at the foot, and
   sat on the cards' words. A soft frosted patch under it (its own element, beside the arrow: the arrow
   is drawn at part opacity, and a blur inside it could see nothing behind), feathered to nothing at its
   edges, blurs and lifts what is beneath just there, so the arrow reads on its own and no word runs
   through it; it comes and goes with the arrow while Search is on show (winter32.js cueOn, cueOff). */
.cue-halo { display: none; }
.story-on .cue-halo { display: block; position: absolute; z-index: 11; left: 50%; bottom: calc(max(12px, 2.2vh) - 16px); width: 110px; height: 70px; margin-left: -55px; background: rgba(252,251,248,.78); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); -webkit-mask: radial-gradient(closest-side, #000 45%, transparent); mask: radial-gradient(closest-side, #000 45%, transparent); opacity: 0; visibility: hidden; pointer-events: none; }
html.night.story-on .cue-halo { background: rgba(13,18,25,.6); }

/* ---------- Round 33 ---------- */
/* The melt (winter33.js scrollOn): Search's page is masked as it goes, a gradient drawn each frame in
   the page's own frame; one copy of it, never tiled. */
.story-on .app { -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; }
/* (Round 33's first answer to "account for the empty space at the top once the finder and icon are
   removed", Search's line moved up into the brand's band, is gone: Anthony, "After seeing the demo page
   without the arc, I realize we need it back", so Finder is back for Search, as in Round 32.) */
/* No band where Finder was (winter33.js made): while Finder is away, his belief's scene reaches up over
   the header's row to the screen's top, so the sentence is centred on the screen; once Finder has faded,
   the story no longer clips at that row's edge, so words leaving upward go out through the screen's own
   edge rather than vanishing at an invisible line. Phone and desktop alike. */
html.story-on #ab-stage > .bar[data-away] ~ .about .sc-made { top: calc(-1 * var(--band, 66px)); }
html.story-on #ab-stage > .bar[data-open] ~ .about { overflow-y: visible; }
html.story-on #ab-stage > .bar[data-end] ~ .about .sc-end { top: calc(-1 * var(--band, 66px)); }

/* ---------- Round 33: an opened card on a desktop ---------- */
/* Anthony: "improve the display of the Search Page on Desktop in the very same way as we did for mobile
   earlier… Give me five options to choose from in how each text field in the Cards are displayed."
   Round 32's desktop card ran every field as "Label: value" in a bold muted label, one under the next,
   in a 62ch column, so five short facts each took a line and the card's right half stood empty. Every
   way here takes the phone's (Round 29's Stack + pair, his pick) treatment of a field: the label small
   (13px, 500, the muted ink, no colon) over its value; they differ in how the six fields are laid out
   (the dcard switch). Search's results and About's Search alike, as on the phone; a phone is unchanged.
     stack   as on his phone: the professor, the time and the description one under the next, then
             Bruinwalk and A% side by side, then the GEs, in the same readable column;
     strip   the five facts across the top in one row, what a student scans first (who, when, how
             it's rated, what it counts for), then the description under them at a reading measure;
     side    the description on the left, the facts in a column beside it, as a detail panel: the
             card's whole width in use, the paragraph at about 60 characters;
     ledger  the labels in a column of their own and the values beside them, every value starting on
             one line, so the eye runs straight down the values;
     lead    the description first, as the thing to read, then a hairline and the facts across in a row.
   "lines" is Round 32's, to compare. */
@container page (min-width: 761px) {
  html:not([data-dcard="lines"])[data-dcard] .fields { font-size: 15.5px; line-height: 1.5; }
  html:not([data-dcard="lines"])[data-dcard] .fields dt { display: block; font-size: 13px; line-height: 1.45; font-weight: 500; letter-spacing: .012em; color: var(--muted); }
  html:not([data-dcard="lines"])[data-dcard] .fields dt::after { content: none; }
  html:not([data-dcard="lines"])[data-dcard] .fields dd { display: block; }
  html:not([data-dcard="lines"])[data-dcard] .fields > div { display: grid; align-content: start; gap: 2px; }
  html:not([data-dcard="lines"])[data-dcard] .fields > .f-desc dd { line-height: 1.6; }

  html[data-dcard="stack"] .fields { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 28px; row-gap: 14px; max-width: 62ch; }
  html[data-dcard="stack"] .fields > div { grid-column: 1 / -1; }
  html[data-dcard="stack"] .fields > .f-prof { order: 1; }
  html[data-dcard="stack"] .fields > .f-meets { order: 2; }
  html[data-dcard="stack"] .fields > .f-desc { order: 3; }
  html[data-dcard="stack"] .fields > .f-bw { order: 4; grid-column: auto; }
  html[data-dcard="stack"] .fields > .f-a { order: 5; grid-column: auto; }
  html[data-dcard="stack"] .fields > .f-ge { order: 6; }

  /* Round 33, later (A% without its count, below): the five facts are one row of a grid, never
     wrapping, each as wide as what it says, with the GEs taking all that's left, so a course
     satisfying three GEs keeps them on one line. The description spans the row under them. */
  html:is([data-dcard="strip"], [data-dcard="lead"]) .fields { display: grid; grid-template-columns: repeat(4, auto) minmax(8rem, 1fr); justify-content: start; column-gap: 48px; row-gap: 16px; max-width: none; }
  html:is([data-dcard="strip"], [data-dcard="lead"]) .fields > div { min-width: 0; }
  html:is([data-dcard="strip"], [data-dcard="lead"]) .fields > .f-desc { grid-column: 1 / -1; }
  html:is([data-dcard="strip"], [data-dcard="lead"]) .fields > .f-desc dd { max-width: 68ch; }
  html[data-dcard="strip"] .fields > .f-prof { order: 1; }
  html[data-dcard="strip"] .fields > .f-meets { order: 2; }
  html[data-dcard="strip"] .fields > .f-bw { order: 3; }
  html[data-dcard="strip"] .fields > .f-a { order: 4; }
  html[data-dcard="strip"] .fields > .f-ge { order: 5; }
  html[data-dcard="strip"] .fields > .f-desc { order: 6; padding-top: 4px; }
  html[data-dcard="lead"] .fields > .f-desc { padding-bottom: 16px; border-bottom: 1px solid rgba(22,51,79,.09); }

  html[data-dcard="side"] .fields { grid-template-columns: minmax(0, 1.65fr) minmax(11.5rem, 1fr); column-gap: 52px; row-gap: 13px; max-width: none; }
  html[data-dcard="side"] .fields > div { grid-column: 2; }
  html[data-dcard="side"] .fields > .f-desc { grid-column: 1; grid-row: 1 / span 5; }

  html[data-dcard="ledger"] .fields { row-gap: 11px; max-width: 76ch; }
  html[data-dcard="ledger"] .fields > div { grid-template-columns: 7.5rem minmax(0, 1fr); column-gap: 20px; align-items: baseline; }
  html[data-dcard="ledger"] .fields > .f-prof { order: 1; }
  html[data-dcard="ledger"] .fields > .f-meets { order: 2; }
  html[data-dcard="ledger"] .fields > .f-desc { order: 3; }
  html[data-dcard="ledger"] .fields > .f-bw { order: 4; }
  html[data-dcard="ledger"] .fields > .f-a { order: 5; }
  html[data-dcard="ledger"] .fields > .f-ge { order: 6; }
}

/* ---------- Round 33: A% without its count of grades ---------- */
/* Anthony: "for desktop only, get rid of the number of grades under A%, on both About and the demo.
   There's always going to be a sufficient number of students who've taken the class. Just show the
   percentage number itself." An opened card's A% reads "44", not "44 (906 Grades)", in Search and
   in About's Search alike; the count stays in the row number's hover title. A phone keeps the count
   unless the agrades switch (his to try) says "bare". */
@container page (min-width: 761px) { .fields .a-n { display: none; } }
html[data-agrades="bare"] .fields .a-n { display: none; }

/* ---------- Round 33: the arrow on a phone ---------- */
/* Anthony: "emphasize the arrow scroll hint on mobile a bit more." A fifth larger (36px), a heavier
   stroke (2.1, from 1.7) and a darker ink (between the muted grey and the ink), with its frosted patch
   grown to match; its opacity and travel are set in winter33.js (CUE). */
@media (max-width: 760px) {
  .story-on .cue { width: 36px; height: 36px; margin-left: -18px; }
  html.story-on:not(.night) .cue { color: #3F5973; }
  .cue svg { stroke-width: 2.1; }
  .story-on .cue-halo { width: 132px; height: 84px; margin-left: -66px; bottom: calc(max(12px, 2.2vh) - 20px); }
}

/* ---------- Round 33: "Fulong, Taiwan" under the opened portrait ---------- */
/* Its place under the photograph's bottom-left corner (winter33.js Photo), in the small caption's italic,
   read across now, at a caption's size: placed on the screen, over everything, never taking a press. */
.place-open { position: fixed; z-index: 30; font-family: var(--f-body); font-style: italic; font-weight: 400; font-size: 13.5px; line-height: 1.3; letter-spacing: .01em; color: var(--muted); white-space: nowrap; pointer-events: none; visibility: hidden; opacity: 0; }
@media (max-width: 760px) { .place-open { font-size: 12.5px; } }
html.night .place-open { color: #97A2AE; } /* night's muted ink (it lives outside .ab-stage, where night sets it) */

/* ---------- Round 33: a mouse's click on a desktop ---------- */
/* The pointer that opens LIFESCI 15 on a desktop (winter33.js clickTl): a plain arrow, ink with a white
   edge as a system pointer is, its tip at the spot (the hotspot is the element's top-left); and the
   faint ring its click leaves. */
.app .ptr { position: absolute; z-index: 6; left: 0; top: 0; width: 18px; height: 25px; margin: -2px 0 0 -2px; transform-origin: 2px 2px; pointer-events: none; visibility: hidden; filter: drop-shadow(0 1px 1.5px rgba(22,51,79,.28)); }
.app .ptr svg { display: block; width: 100%; height: 100%; }
.app .ptr path { fill: #16334F; stroke: #fff; stroke-width: 1.4; stroke-linejoin: round; }
.app .ptr-ring { position: absolute; z-index: 5; left: 0; top: 0; width: 30px; height: 30px; margin: -15px 0 0 -15px; border-radius: 50%; border: 1.5px solid rgba(22,51,79,.22); pointer-events: none; visibility: hidden; }

/* ---------- Production: what the live backend adds ---------- */
/* No answer (oops, search.js), in the conversation and Search alike: the Pill. The line reads as an
   answer would, in ink; Try again carries the New chat glyph. Search's sits where the first row lands. */
.oops p { color: var(--ink); text-wrap: pretty; }
.oops .again { margin-top: 10px; display: inline-flex; align-items: center; gap: 7px; font-size: 14px; font-weight: 500; color: var(--ink); border: 1px solid rgba(22,51,79,.22); border-radius: 999px; padding: 6px 14px 6px 12px; transition: border-color .15s; }
.oops .again svg { width: 15px; height: 15px; color: var(--muted); }
.oops .again:hover { border-color: rgba(22,51,79,.45); }
#bread .oops { padding-right: 16px; }
#bread.failed .bb-wait { display: block; }
#bread.failed:not(.waiting) .bb-wait { padding-bottom: 12px; }

/* ---------- Round 34: Search's cards a little smaller ---------- */
/* Anthony: "the course cards just a little bit smaller. There's that in-your-face feel again." Search
   itself only; About's demo stays as it was. About a tenth off the type and the padding. */
#bread .bb { max-width: 840px; }
#bread .card summary { padding: 12px 16px 12px 14px; column-gap: 12px; }
#bread .card .title { font-size: 15.5px; }
#bread .card .code { font-size: 11.5px; }
#bread .card .rank { font-size: 12.5px; }
#bread .num b { font-size: 14px; }
#bread .num small { font-size: 11px; }
#bread .card .body { padding: 0 16px 14px 40px; }
@container page (min-width: 761px) {
  html:not([data-dcard="lines"])[data-dcard] #bread .fields { font-size: 14.5px; }
  html:not([data-dcard="lines"])[data-dcard] #bread .fields dt { font-size: 12.5px; }
}
@container page (max-width: 760px) {
  #bread .card .body { padding: 0 14px 14px; }
  html[data-mcard] #bread .fields { font-size: 14px; }
}

/* ---------- Round 34: the landing, toned down ---------- */
/* Anthony: "Everything on the landing page feels a bit big and in-your-face. I didn't realize it in
   Artifacts because it wasn't usually presented in full screen… tone down the size of everything a
   little bit in a way that feels natural." About a sixth off everything, in proportion: the line
   (54px to 44px at most), the bunch (360px to 304px wide, in index.html's DESIGN.plate), its labels,
   their ripeness tags, and the Ask bar's words and measure. */
#hero { --hero-size: clamp(30px, 4.3vw, 44px); }
.label { max-width: 210px; }
.label b { font-size: 15px; }
.label small { font-size: 13px; }
.label .stat { font-size: 10px; padding: 2px 6px; }
.ask-wrap { max-width: 600px; margin-top: clamp(24px, 4.6vh, 50px); }
#home form.composer textarea { font-size: 16px; line-height: 25px; height: 25px; }
#home .hint { font-size: 16px; line-height: 25px; }
#home .send { font-size: 14px; }
@container page (max-width: 760px) {
  #hero { --hero-size: 30px; }
  .plate.phone .label { max-width: 158px; }
  .plate.phone .label b { font-size: 14px; }
  .plate.phone .label small { font-size: 12.5px; }
}

/* Round 34: on a desktop the opened portrait keeps a hairline of its white mount, and a soft shadow
   (Photo sets how far the photograph grows over it). */
@container page (min-width: 761px) {
  .pic[aria-expanded="true"], html.night .pic[aria-expanded="true"] { background-color: var(--surface); box-shadow: 0 1px 2px rgba(22,51,79,.12), 0 30px 60px -34px rgba(22,51,79,.45); } /* taste-skill-ignore: his photograph as a print, a hairline of its mount */
}

/* Round 35: on a desktop the cards keep main's left column, the thumbs beside them, and the four
   short facts go across (each kept on one line), then the GEs, then the description. A phone's
   column is too narrow to spare the thumbs theirs, so there the cards take the whole width, as the
   thumbs sit on the "Sources" line above them. */
@container page (min-width: 761px) {
  .msg-foot details.sources { grid-column: 1; }
  #thread .source-card .fields { grid-template-columns: repeat(4, auto); justify-content: start; column-gap: 30px; }
  #thread .source-card .fields > .f-bw { order: 3; }
  #thread .source-card .fields > .f-a { order: 4; }
  #thread .source-card .fields > .f-ge { order: 5; }
  #thread .source-card .fields > .f-desc { order: 6; padding-top: 1px; }
  #thread .source-card .fields > :is(.f-meets, .f-bw, .f-a) dd { white-space: nowrap; }
}
@container page (max-width: 760px) {
  #thread .turn > .a { padding-left: 14px; }
}

/* Round 34: the rolling examples in the Ask bar, drawn as Search's line draws its suggestions. */
/* Round 36: the hint box is the room the bar keeps (--hint-lines), and each example sits on its
   bottom line, as typed text does, however many lines the one before it had. */
#home .hint { display: block; -webkit-line-clamp: unset; height: calc(var(--hint-lines, 1) * 25px); overflow: hidden; }
/* Round 39: across the bar's whole width as typed words would wrap, never one word alone below. */
#home .hint .rw { position: absolute; left: 0; bottom: 0; max-width: 100%; text-wrap: pretty; }
#home .hint .rw span { display: inline-block; white-space: pre; }
/* Round 34 (Anthony: "a lot of empty space at the bottom of the landing page, now that things were
   made smaller… spacing the elements out a little more in a natural way"): the landing fills the
   screen, its three parts spread down it, the gaps growing with the screen's height. */
@media (min-height: 720px) {
  #home:not([hidden]) { min-height: 100svh; display: flex; flex-direction: column; }
  #home .landing { flex: 1; width: 100%; display: flex; flex-direction: column; justify-content: center; padding-top: clamp(4px, 2vh, 32px); padding-bottom: clamp(10px, 6vh, 100px); }
  #home .stage { margin-top: clamp(14px, 4.6vh, 60px); }
  #home .ask-wrap { margin-top: clamp(20px, 6.4vh, 86px); }
  /* Round 35: in this column an auto-margined block shrinks to its content (the bar was 246px wide
     on a laptop); it takes the column's width, up to its own max-width, again. */
  #home .ask-wrap { width: 100%; }
}
/* Round 35: the bar keeps room above its line for the tallest rolling example (Roll's --hint-lines),
   so an example of two lines never reaches the Search tab above it. */
#home form.composer { min-height: calc(var(--hint-lines, 1) * 25px + 10px); }

/* ---------- Round 45: the landing and the conversation, his picks from Rounds 40-45 ---------- */
/* Round 40, Closer together: the heading, bunch and bar drawn together, the bunch 336px
   (DESIGN.plate in index.html). */
#home .stage { margin-top: clamp(10px, 2.4vh, 28px); }
#home .ask-wrap { margin-top: clamp(16px, 2.8vh, 34px); max-width: 580px; }
@media (min-height: 720px) { #home .landing { padding-bottom: clamp(10px, 4vh, 64px); } }
/* Round 42: his tune at 1098×878 ("I like the landing page as I adjusted it"), on any desktop: the
   heading at 44px, the bunch 10px lower, the bar and Search 25px lower, each moving nothing else. */
@container page (min-width: 761px) {
  #hero { --hero-size: 44px; }
  #home .stage { translate: 0 10px; }
  #home form.composer, #home .ask-wrap > .modes { translate: 0 25px; }
}

/* Round 41: Search under the bar, its lens beside it; "Search" lifts in a wave as the labels do. */
#home .modes { margin: 12px 0 0 -12px; }
.modes .lens { display: block; width: 15px; height: 15px; margin-right: -2px; }
.mode .bb-name .wd { white-space: nowrap; }
.mode .bb-name .ch { display: inline-block; transition: transform .3s var(--ease); transition-delay: calc(var(--i) * 16ms); }
.mode.to-bb:hover .bb-name .ch, .mode.to-bb:focus-visible .bb-name .ch { transform: translateY(-1.5px); }
/* Round 40: the bar keeps one line's room, an example as wide as the bar's tools allow (--side,
   landing.js), and a two-line example grows the bar upward only while it shows (.two). */
#home .hint { right: var(--side, 70px); }
#home .ask-wrap > .modes, #home form.composer { transition: translate .45s var(--ease), margin-top .45s var(--ease), min-height .45s var(--ease); }
#home .ask-wrap.two form.composer { --hint-lines: 2; margin-top: -25px; }
/* Round 49 (Anthony, on an iPhone 14: a two-line example ran up into "Bruinwalk Ratings" and its tag):
   a phone has no room above the bar to grow into, so it keeps two lines' room all the time, and a long
   example fills it in place; nothing above or below moves. */
@container page (max-width: 760px) { #home form.composer, #home .ask-wrap.two form.composer { --hint-lines: 2; margin-top: 0; } }

/* ---- Round 49: Search's Send off, its question back in the line, the tip on hover or tap ---- */
/* A copy of the question laid over the line's own text (search.js send()): its size, place and ink. */
.bb-out { grid-area: 1 / 1; z-index: 2; align-self: start; font-size: 17.5px; line-height: 28px; color: var(--ink); pointer-events: none; }
.bb-out span { display: inline-block; white-space: pre; }
/* What was asked, back in the line in its own ink; the tip, typed over a hidden copy of itself that
   holds its room, so the line doesn't grow a letter at a time. */
.bb-ghost .g.asked { color: var(--ink); opacity: 1; }
.bb-ghost .g.tip { position: relative; display: block; }
.bb-ghost .g.tip > span { display: block; white-space: normal; }
.bb-ghost .g.tip .sizer { visibility: hidden; }
.bb-ghost .g.tip .typed { position: absolute; inset: 0; }
@container page (max-width: 760px) { .bb-out { font-size: 17px; } }

/* Round 45, the wait: chat.js breathes the flake and each letter from one clock, so the CSS breath
   is off here (the flake's turn is GSAP's). The word sits optically on the flake's centre: its box
   is trimmed to the x-height (text-box), then lowered by half the gap to the cap height (.05em) and
   a quarter pixel (Anthony: "half of the difference"). A letter shrinks standing on its baseline. */
.wait { display: flex; align-items: center; gap: 9px; height: 30px; }
.wait.going { position: absolute; top: 0; left: 0; right: 0; pointer-events: none; }
#thread .turn > .a { position: relative; }
.wait .fl { display: grid; flex: none; }
.loader.wait .fl svg g { animation: none; }
.wait .word { font-size: 15px; font-weight: 500; line-height: 1; white-space: nowrap; color: var(--muted); text-box: trim-both ex alphabetic; translate: 0 calc(.05em + .25px); }
.wait .txt { display: inline-block; }
.wait .ch { display: inline-block; transform-origin: 50% 82%; }
.wait .ch.dot { margin-left: .01em; }   /* Round 46: the dots, as Round 45's r45.css set them */

/* Round 40, Slip: the closing question set apart. Round 46: the picks are main's bullets again
   (.answer ul above), and every line is .answer's one size (Slip's 17px first line made an answer
   that opens with two paragraphs change size between them). */
.answer ul + p:last-child { color: var(--muted); margin-top: 16px; }
