/* Profile screen: the room the game is in, with the problem board in it.
   Who you are on the left, what there is to climb on the right.

   This screen used to be a dark panel with translucent cards floating on it,
   and it was the only surface in the project that was not made of the game's
   own materials. Two things settled that. `Portrait` clears to alpha 0 — the
   comment in `buildBackdrop` says as much — so whatever is behind the canvas
   IS the room the climber is standing in, and a navy void is a strange room for
   a gym. And the renderer draws in flat bands with an ink outline round
   everything (see render/toon.js), which is a drawing language the interface can
   speak too.

   So: the page is the wall, on the gym's own 30 cm T-nut grid and 4 ft ply
   (gym.js `step`, WALL.panelSize), painted in the panel tones from COLORS. The
   problem is a card taped to it. Every colour below is one the game already
   renders, and the only shadows are hard ones — a shadow on this screen means
   the object stands off the wall, which is why the route card, the tape and the
   buttons have one and nothing else does.

   Two ink tones, not a ladder of opacities: --pen for anything being read,
   --pencil for anything being labelled. If a third is wanted, the answer is
   almost always that the thing wanting it is too important to be muted. */

#profile {
  /* The surfaces this screen is made of and the HUD is not — straight out of
     COLORS in config.js, which is what the wall behind the canvas is actually
     painted with. */
  --ply:    #b3c5d2;
  --ply-d:  #aabecc;
  --pad:    #264653;      /* COLORS.padSide */
  /* COLORS.volume, both tones: the lit face and the one turned away. Warm, and
     the only warm thing on this wall, for the reason written beside it in
     config.js — a form whose lit face matches the surface behind it has no
     silhouette, so a volume in the panels' own blue is a ghost of the wall. */
  --vol:    #a39c92;
  --vol-d:  #827c73;

  /* ...and the rest named for what they are HERE, out of the shared palette in
     hud.css rather than restated. The values are the same colours the HUD uses
     for other jobs — this screen's tape is the HUD's problem colour is the
     game's `COLORS.problem` — and two files holding one value is two files that
     can drift apart, which is the whole warning at the top of config.js. */
  --pen:    var(--ink);
  --chalk:  var(--paper);
  --tape:   var(--coral);
  --send:   var(--good);
  --flash:  var(--warn);

  /* How far anything stuck to the wall stands off it. A pixel more than the
     HUD's: a card on a menu is nearer the reader than a tag on a wall the
     camera is looking at. */
  --lift: 4px;

  position: fixed;
  top: 0; left: 0; right: 0;
  height: 100vh;
  height: 100dvh;      /* same iOS URL-bar problem as #viewport — see hud.css */
  z-index: 20;
  display: grid;
  grid-template-columns: minmax(320px, 38%) 1fr;
  color: var(--pen);
  transition: opacity .45s ease, visibility .45s;

  /* The wall, from the back forward: ply panels, seams, T-nuts. The pitches are
     the gym's — 30 cm between nuts, 1.22 m panels, so 4.07 nuts to a panel, and
     34 px keeps that ratio at a size a screen can show. */
  background-color: var(--ply);
  background-image:
    radial-gradient(circle at 50% 50%,
      rgba(43, 34, 51, .17) 0 1.6px, rgba(43, 34, 51, 0) 1.7px),
    linear-gradient(90deg, rgba(43, 34, 51, .09) 0 2px, rgba(43, 34, 51, 0) 2px),
    linear-gradient(180deg, rgba(43, 34, 51, .09) 0 2px, rgba(43, 34, 51, 0) 2px),
    repeating-conic-gradient(var(--ply-d) 0 25%, var(--ply) 0 50%);
  background-size: 34px 34px, 138px 138px, 138px 138px, 276px 276px;
}
#profile.hidden { opacity: 0; visibility: hidden; }

/* Ink, not a hairline: this screen is drawn, and a 1 px 8%-white rule is the
   one thing in it that would not be. */
#profile :focus-visible {
  outline: 3px solid var(--pen);
  outline-offset: 3px;
}

/* ---------------- left: the climber ---------------- */

.pf-stage {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0; min-height: 0;
  border-right: 3px solid var(--pen);
}

#portrait {
  display: block;
  width: 100%;
  flex: 1 1 0;
  min-height: 0;      /* or the canvas's own pixel height sets the floor and
                         the panel below it is pushed off the screen */
  /* The character does not respond to a pointer, so nothing here may eat one:
     on a phone this canvas fills the top of a screen that scrolls, and a swipe
     that starts on it has to scroll the page like any other. */
  touch-action: auto;
}

/* The crash pad, seen edge-on — which is the only thing that can be below the
   floor line the canvas above ends on. A kickboard was tried here first and is
   wrong: a kickboard is the bottom of the WALL, so putting one under the floor
   stacks the room in an order no gym is built in. The pad is in front of the
   climber and slightly below their feet, which is where this band lands. */
.pf-plate {
  position: relative;
  background: var(--pad);
  border-top: 3px solid var(--pen);
  padding: 0 24px 24px;
  text-align: center;
  color: var(--chalk);
}
.pf-plate :focus-visible { outline-color: var(--chalk); }

/* Stuck across the seam, half on the floor and half on the pad, the way tape
   actually goes on. The rotation is the only thing selling it, so it is small
   and it is the only rotation on this side of the screen. */
.pf-tape {
  display: inline-block;
  position: relative;
  width: min(82%, 300px);
  margin: -22px 0 0;
  padding: 7px 20px 9px;
  rotate: -1.4deg;
  /* The same chalk as the route card, not a warmer tape-white: the two are
     never on screen next to each other, so the distinction would buy nothing
     and cost this file the one rule it has — that every colour on this screen
     is a colour the game already renders. */
  background: var(--chalk);
  border: 2px solid var(--pen);
  border-radius: 2px;
  box-shadow: 3px 3px 0 var(--cast);
}

.pf-name {
  width: 100%;
  appearance: none; background: transparent;
  border: 0;
  color: var(--pen);
  font: inherit; font-weight: 1000; font-size: 25px; letter-spacing: -.025em;
  text-align: center;
  padding: 0;
}
.pf-name::selection { background: var(--tape); color: var(--pen); }

/* Says what to do with the strip above it, and nothing else.

   The three alphas on this dark band are all .72 rather than the .3-.5 a label
   usually gets, because chalk thinned over the pad washes out fast: at .5 it
   lands on 3.4:1 and a 9 px legend at 3.4:1 is decoration. */
.pf-hint {
  margin-top: 13px;
  font-family: var(--mono);
  font-size: 9px; letter-spacing: .16em; text-transform: uppercase;
  color: rgba(244, 241, 234, .72);
}
/* Same pattern as the two control lists below: both are in the DOM and `.touch`
   on the body picks which one is displayed. */
.pf-hint-touch { display: none; }
body.touch .pf-hint { display: none; }
body.touch .pf-hint-touch { display: block; }

.pf-career {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin: 20px 0 20px;
}
.pf-career span {
  display: block;
  font-size: 27px; font-weight: 1000; letter-spacing: -.035em;
  font-variant-numeric: tabular-nums;
}
.pf-career span i { font-size: 12px; font-style: normal; opacity: .55; margin-left: 1px; }
.pf-career b {
  display: block; margin-top: 5px;
  font-family: var(--mono); font-size: 9px; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
  color: rgba(244, 241, 234, .72);
}

/* Nothing behind it yet, so it is drawn as an empty slot rather than as a
   button that has been switched off. */
#pfCustomise {
  appearance: none;
  width: 100%;
  background: transparent; color: rgba(244, 241, 234, .72);
  border: 2px dashed rgba(244, 241, 234, .28);
  border-radius: 6px;
  font: inherit; font-family: var(--mono);
  font-size: 10px; letter-spacing: .16em; text-transform: uppercase;
  padding: 12px 14px;
}
#pfCustomise em {
  font-style: normal;
  color: rgba(244, 241, 234, .32);
  margin-left: 6px;
}
#pfCustomise[disabled] { cursor: default; }

/* ---------------- right: the board ---------------- */

.pf-list {
  min-width: 0;
  /* The tape flag on the route card hangs 30 px off its left edge, into this
     padding — which is why the left has a floor the others do not. */
  padding: clamp(24px, 4.2vh, 46px) clamp(22px, 4vw, 54px);
  padding-left: max(clamp(34px, 4vw, 54px), env(safe-area-inset-left));
  padding-right: max(clamp(22px, 4vw, 54px), env(safe-area-inset-right));
  padding-bottom: max(clamp(24px, 4.2vh, 46px), env(safe-area-inset-bottom));
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  display: flex; flex-direction: column; align-items: start;
}

/* A board on a wall is a fixed size and the wall is whatever is left. Without
   this the route card grows to whatever a monitor is wide, and a 1200 px card
   holding one paragraph reads as a page that has run out of things to say. */
.pf-list > * { width: 100%; max-width: 780px; }

/* The gym's name, painted on the wall it is the name of. `multiply` is what
   makes it paint rather than a label: the panel tones and the T-nuts come
   through it, so it sits IN the ply instead of on top of it. */
.pf-brand {
  display: flex; flex-direction: column;
  margin-bottom: clamp(26px, 4vh, 44px);
  font-size: clamp(28px, 4vw, 54px);
  font-weight: 1000;
  line-height: .84;
  letter-spacing: -.04em;
  text-transform: uppercase;
  color: var(--pen);
  mix-blend-mode: multiply;
}
.pf-brand em { font-style: normal; color: var(--tape); }

.pf-listhead {
  display: flex; align-items: baseline; gap: 12px;
  border-bottom: 3px solid var(--pen);
  padding-bottom: 9px;
  margin-bottom: 30px;
}
.pf-listhead h2 {
  margin: 0;
  font-family: var(--mono); font-size: 11px; font-weight: 700;
  letter-spacing: .22em; text-transform: uppercase;
}
.pf-listhead span {
  margin-left: auto;
  font-family: var(--mono); font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--pencil);
}

/* ---- one problem ---- */

/* A printed card on the wall, so it is the one white thing on this screen and
   all the reading happens on it. */
.route {
  position: relative;
  display: grid;
  grid-template-columns: 76px 1fr;
  gap: 22px;
  padding: 22px 26px 24px;
  background: var(--chalk);
  border: 2px solid var(--pen);
  border-radius: 5px;
  box-shadow: var(--lift) var(--lift) 0 var(--cast);
}

/* The tape flag. In a gym the grade is written on a strip of the problem's own
   colour stuck beside the start hold — so it is that colour, it is stuck across
   the corner rather than set into the card, and it is the only place a hold
   colour appears at this size. */
.route-grade {
  display: grid; justify-items: center; gap: 1px;
  align-self: start;
  margin: -34px 0 0 -30px;
  padding: 10px 0 9px;
  rotate: -4deg;
  background: var(--tape);
  border: 2px solid var(--pen);
  border-radius: 2px;
  box-shadow: 3px 3px 0 var(--cast);
}
.route-grade b { font-size: 30px; font-weight: 1000; letter-spacing: -.04em; line-height: 1; }
/* Full ink, not a faded one: this is the Font grade, the other half of what the
   tape says, and thinned to .62 over coral it reads 2.7:1. */
.route-grade i {
  font-family: var(--mono); font-style: normal;
  font-size: 10px; font-weight: 700; letter-spacing: .06em;
}

.route-body { min-width: 0; }
.route-top { padding-right: 92px; }     /* clear of the stamp, which is absolute */
.route-top h3 {
  margin: 0;
  font-size: clamp(26px, 3.1vw, 37px);
  font-weight: 1000;
  letter-spacing: -.04em;
  line-height: .96;
  text-transform: uppercase;
}

/* A stamp, and stamps are never straight. Off the card's edge because that is
   where one lands when someone is stamping a stack of them. */
.route-status {
  position: absolute;
  top: 18px; right: -12px;
  rotate: 6deg;
  padding: 6px 10px 5px;
  border: 2px solid var(--pencil);
  border-radius: 3px;
  font-family: var(--mono); font-size: 10px; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--pencil);
  white-space: nowrap;
}
.route-status.sent {
  color: var(--pen); border-color: var(--pen);
  background: var(--send);
  box-shadow: 2px 2px 0 var(--cast);
}
.route-status.flashed {
  color: var(--pen); border-color: var(--pen);
  background: var(--flash);
  box-shadow: 2px 2px 0 var(--cast);
}

.route-setter {
  margin-top: 8px;
  font-family: var(--mono); font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--pencil);
}
.route-note {
  margin: 14px 0 0;
  font-size: 14.5px; line-height: 1.55; max-width: 52ch;
}

/* Four measurements, read as measurements: the number is the thing, the label
   is the label. Chips would have made all four the same size as each other and
   the same size as the crux, which is the one that is not a measurement. */
.route-facts {
  display: flex; flex-wrap: wrap; gap: 8px 30px;
  margin-top: 20px;
  padding-top: 16px;
  border-top: 2px solid rgba(43, 34, 51, .13);
}
.route-facts > div { display: grid; gap: 3px; }
.route-facts b {
  font-size: 23px; font-weight: 1000; letter-spacing: -.035em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.route-facts b i { font-style: normal; font-size: 13px; margin-left: 1px; }
.route-facts span {
  font-family: var(--mono); font-size: 9px;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--pencil);
}

/* The hard bit, and therefore the darkest mark on the card. It is solid ink
   rather than a third piece of tape: the tape colour on this screen means "this
   problem", and using it again here would make the crux a second problem. */
.route-crux {
  display: flex; align-items: baseline; gap: 10px;
  margin: 18px 0 0;
}
.route-crux b {
  flex: none;
  background: var(--pen); color: var(--chalk);
  border-radius: 3px;
  padding: 5px 8px 4px;
  font-family: var(--mono); font-size: 9px; font-weight: 700; letter-spacing: .2em;
}
.route-crux span { font-size: 14px; font-weight: 700; }

.route-foot { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 18px; margin-top: 24px; }

/* Pressable things move: over by the width of their own shadow, so the object
   goes down onto the card rather than glowing at you. */
#startBtn {
  appearance: none; cursor: pointer;
  background: var(--tape); color: var(--pen);
  border: 2px solid var(--pen); border-radius: 6px;
  font: inherit; font-weight: 1000; font-size: 15px;
  letter-spacing: .16em; text-transform: uppercase;
  padding: 14px 34px;
  box-shadow: var(--lift) var(--lift) 0 var(--pen);
  transition: translate .1s ease, box-shadow .1s ease;
}
#startBtn:hover { translate: -1px -1px; box-shadow: 5px 5px 0 var(--pen); }
#startBtn:active { translate: var(--lift) var(--lift); box-shadow: 0 0 0 var(--pen); }
#startBtn[disabled] {
  cursor: default;
  background: rgba(43, 34, 51, .05);
  color: var(--pencil); border-color: var(--pencil);
  box-shadow: 2px 2px 0 rgba(43, 34, 51, .18);
  translate: none;
}

.route-record {
  font-family: var(--mono); font-size: 10.5px;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--pencil);
}

/* The four empty slots, drawn as empty slots. It is flat on the wall — nothing
   has been stuck up there yet — so it is the one block here with no shadow. */
.pf-more {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px;
  margin-top: 20px;
  padding: 17px 22px;
  border: 2px dashed rgba(43, 34, 51, .26);
  border-radius: 5px;
}
.pf-more b {
  font-family: var(--mono); font-size: 10px; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase;
}
.pf-more span { font-size: 13px; color: var(--pencil); }

/* ---- controls, kept out of the route card: they are not route-specific ---- */

/* Directly under the list, not pinned to the bottom of the pane: with one
   problem set, a bottom-pinned block leaves a hole in the middle of the screen
   and the empty space reads as missing rather than as room to grow. */
.pf-keys {
  padding-top: 46px;
  display: flex; flex-direction: column;
}
.pf-keys-title {
  font-family: var(--mono); font-size: 10px; font-weight: 700;
  letter-spacing: .22em; text-transform: uppercase;
  border-bottom: 3px solid var(--pen);
  padding-bottom: 9px;
  margin-bottom: 6px;
}
.pf-keys > div:not(.pf-keys-title) {
  display: flex; align-items: center; gap: 5px;
  margin-top: 9px;
  font-size: 13px;
}
/* Outlined, not raised: these are legends for keys that are somewhere else, so
   nothing here is standing off the wall. */
.pf-keys b {
  display: inline-grid; place-items: center;
  min-width: 26px; height: 25px; padding: 0 7px;
  background: var(--chalk);
  border: 2px solid var(--pen); border-radius: 5px;
  font-family: var(--mono); font-size: 10px; font-weight: 700;
}
/* The HUD gives each limb a colour and this is where a player meets it. Values
   from --lh/--rh/--lf/--rf in hud.css, which is where the HUD reads them. */
.pf-keys b[data-limb="LH"] { background: var(--lh); }
.pf-keys b[data-limb="RH"] { background: var(--rh); }
.pf-keys b[data-limb="LF"] { background: var(--lf); }
.pf-keys b[data-limb="RF"] { background: var(--rf); }
.pf-keys span { margin-left: 8px; color: var(--pencil); }

/* One of the two is on screen at a time; `.touch` on the body picks which.
   See the note on the pair in index.html. */
.pf-keys-touch { display: none; }
body.touch .pf-keys { display: none; }
body.touch .pf-keys-touch { display: flex; }

/* ---- support ---- */

/* Buy Me a Coffee's own button is a PNG their server renders on request. Every
   other asset here is local for the reason written at the top of hud.css: the
   game runs off `npm start` with no network, and a thing that arrives from a
   CDN — or does not — lays the page out differently on the frame it lands.
   That frame is a menu the player is reading. So the button is drawn here in
   the colours the button-api URL asked for (FFDD00, black text and outline,
   white cup) and points at the same page. It inherits this screen's own face
   and its ink line rather than the Poppins and the pure black that URL asks
   for: the only faces here are the ones in assets/fonts, which is the whole
   point of the paragraph above.

   Under the controls, not pinned to the foot of the pane, for the same reason
   the controls are not: with one problem set there is nothing to push it
   down with, and the gap would read as missing content. */
.pf-support {
  padding-top: 34px;
  display: flex; align-items: center; flex-wrap: wrap; gap: 16px;
}
.pf-support > span {
  font-family: var(--mono); font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--pencil);
}

.bmc {
  display: inline-flex; align-items: center; gap: 9px;
  height: 46px; padding: 0 18px;
  background: #ffdd00; color: var(--pen);
  border: 2px solid var(--pen); border-radius: 6px;
  text-decoration: none; white-space: nowrap;
  font-weight: 800; font-size: 15px; letter-spacing: -.005em;
  /* One pixel less than CLIMB throws, and it keeps it: yellow on ply is already
     the loudest thing in the pane, and it is not the button of the screen. */
  box-shadow: 3px 3px 0 var(--pen);
  transition: translate .1s ease, box-shadow .1s ease;
}
.bmc:hover { translate: -1px -1px; box-shadow: 4px 4px 0 var(--pen); }
.bmc:active { translate: 3px 3px; box-shadow: 0 0 0 var(--pen); }
.bmc-cup { width: 22px; height: 22px; flex: none; }
/* Drawn for a black button, and this one is ink — so the cup follows. */
.bmc-cup [fill="#fff"] { fill: var(--pen); }
.bmc-cup [stroke="#fff"] { stroke: var(--pen); }
.bmc-cup [stroke="#000"] { stroke: #ffdd00; opacity: .5; }

/* ---- what the coffee is for ---- */

/* Four slabs bolted to the empty part of the wall. A slab in this project is a
   specific object — WALL_VOLUMES[0], "a squat frustum, the classic box volume"
   — so these are drawn as one rather than as list markers: the cut corner is
   the frustum's taper seen face on, and the darker band inside it is the
   sloped face turned away from the light.

   They are objects, not controls: no radius, because a volume is plywood with
   a router-round at most; no hover, nothing to press. That is the whole reason
   they replaced a row of squares — a 15 px outlined square beside a label is a
   checkbox in every interface anyone has ever used, and this list is not one
   you tick.

   They stand off the wall, so they cast, and the shadow is `drop-shadow` and
   not `box-shadow`: a box shadow is drawn from the border box and would square
   off the very corner the clip just cut. */
.pf-plans { padding-top: 30px; }
.pf-plans-title {
  font-family: var(--mono); font-size: 10px; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--pencil);
  margin-bottom: 14px;
}
.pf-plans ul {
  margin: 0; padding: 0; list-style: none;
  display: flex; flex-wrap: wrap; gap: 12px;
}

/* The ink line is this element showing through 2 px around the face on top of
   it — the outline treatment everything drawn on this screen gets, done with a
   backing shape because a border cannot follow a clip path. */
.pf-plans li {
  --cut: 15px;
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
  background: var(--pen);
  filter: drop-shadow(3px 3px 0 var(--cast));
}
.pf-plans li span {
  /* Same taper 1.2 px shy of the backing shape's. Not the same number, because
     the cut runs at 45° and a 2 px inset perpendicular to a 45° edge is not a
     2 px change in where that edge starts: at an equal `--cut` the ink reads
     2.83 px along the diagonal and 2 px everywhere else, which is a line that
     thickens at one corner for no reason a viewer can see. */
  --face: 5px;
  --icut: calc(var(--cut) - 1.2px);
  display: block;
  margin: 2px;
  padding: 10px 16px 11px;
  clip-path: polygon(0 0, calc(100% - var(--icut)) 0, 100% var(--icut), 100% 100%, 0 100%);
  /* The lit face, and the taper's own face inside it. A gradient measures along
     its axis from the corner it starts at, and this axis is square to the cut,
     so the cut edge sits at cos(45°) of `--icut` and the band is `--face` past
     that — which makes the stop the sloped face itself rather than a gradient
     that happens to land near it. */
  background: linear-gradient(225deg,
    var(--vol-d) 0 calc(var(--icut) * 0.7071 + var(--face)),
    var(--vol)     calc(var(--icut) * 0.7071 + var(--face)));
  font-size: 13.5px; font-weight: 700;
}

/* ---------------- coming in ---------------- */

/* One move, once, on the two things that are the screen: the climber's pane and
   the board beside it. Anything more and the menu would be performing. */
@media (prefers-reduced-motion: no-preference) {
  .pf-stage, .pf-list > * { animation: pfIn .42s ease both; }
  .pf-list > *:nth-child(2) { animation-delay: .05s; }
  .pf-list > *:nth-child(3) { animation-delay: .10s; }
  .pf-list > *:nth-child(n+4) { animation-delay: .15s; }
  @keyframes pfIn {
    from { opacity: 0; translate: 0 10px; }
    to   { opacity: 1; translate: 0 0; }
  }
}

/* ---------------- narrow ---------------- */

@media (max-width: 900px) {
  #profile { grid-template-columns: 1fr; grid-template-rows: minmax(260px, 50vh) auto; overflow-y: auto; }
  .pf-stage { border-right: 0; border-bottom: 3px solid var(--pen); }

  /* Stacked, this band was the whole problem with this screen: the pad is a
     fixed 150 px of chrome and the stage is a fraction of a phone, so the
     climber — the one thing on the screen that is the player — was getting
     90 px of a 240 px pane and reading as a sticker on a wall.

     So the pad goes in FRONT of them, which is where a crash pad is: it is the
     only object here nearer the camera than the body, the canvas clears to
     alpha 0 so the wall carries on behind it, and the fixed cost now comes out
     of floor rather than out of the climber. `Portrait#coveredHeight` measures
     this element and frames the body into what is left, so the shoes stay above
     its edge — the pad is in front of the feet, not over them. */
  .pf-plate { position: absolute; left: 0; right: 0; bottom: 0; padding-bottom: 16px; }
  .pf-hint { margin-top: 10px; }
  .pf-career { margin: 14px 0 0; }
  .pf-career span { font-size: 23px; }
  #pfCustomise { display: none; }

  /* Half of what the stage took, taken back off the wordmark and the gaps
     under it, so the route card does not go the whole way down the page. */
  .pf-brand { font-size: clamp(24px, 7.2vw, 38px); margin-bottom: 18px; }
  .pf-list { padding-top: 22px; }
  .pf-listhead { margin-bottom: 22px; }
  .pf-keys { display: none; }
  /* ...but the touch list stays. A player on a phone has nowhere else to learn
     the scheme, and unlike Q/E/A/D it is not one they have met before. */
  .pf-keys-touch { padding-top: 30px; }
  .pf-support { padding-top: 26px; }
  .route { grid-template-columns: 62px 1fr; gap: 16px; padding: 20px 20px 22px; }
  .route-grade { margin: -28px 0 0 -24px; }
  .route-grade b { font-size: 24px; }
  .route-facts { gap: 8px 22px; }
}

/* A landscape phone: short, and the portrait pane eats the screen before the
   CLIMB button gets any of it. Shrink the stage rather than make the player
   scroll past the model to find the button. */
@media (max-height: 520px) and (orientation: landscape) {
  #profile { grid-template-columns: minmax(210px, 30%) 1fr; grid-template-rows: 1fr; overflow: hidden; }
  .pf-stage { border-right: 3px solid var(--pen); border-bottom: 0; }
  .pf-plate { padding: 0 14px 14px; }
  .pf-tape { width: min(92%, 220px); padding: 5px 12px 6px; margin-top: -16px; }
  .pf-name { font-size: 17px; }
  .pf-hint { display: none; }
  .pf-career { margin: 12px 0 0; }
  .pf-career span { font-size: 17px; }
  .pf-career b { margin-top: 2px; }
  .pf-list { padding: 14px max(16px, env(safe-area-inset-right)) 16px 34px; }
  .pf-brand { display: none; }
  .pf-listhead { margin-bottom: 20px; padding-bottom: 7px; }
  .route { padding: 16px 18px 18px; }
  .route-top h3 { font-size: 22px; }
  .route-note { display: none; }
  .route-facts { margin-top: 14px; padding-top: 12px; }
  .route-facts b { font-size: 18px; }
  .route-foot { margin-top: 16px; }
  #startBtn { padding: 11px 24px; font-size: 13px; }
  .pf-more { display: none; }
  .pf-keys-touch { padding-top: 22px; }
  /* The lead-in goes, the button stays: the button says what it is. */
  .pf-support { padding-top: 22px; }
  .pf-support > span { display: none; }
  .bmc { height: 38px; padding: 0 14px; font-size: 13px; }
  .bmc-cup { width: 18px; height: 18px; }
  /* Tightened rather than dropped like .pf-more above it: the pane scrolls, and
     this is the one block here a reader came for rather than one they read on
     the way past. */
  .pf-plans { padding-top: 20px; }
  .pf-plans-title { margin-bottom: 10px; }
  .pf-plans ul { gap: 9px; }
  /* The taper comes down with the slab. Held at a fixed 15 px it would eat a
     third of the width of a block this size and read as a chamfer rather than
     as a frustum. */
  .pf-plans li { --cut: 12px; }
  .pf-plans li span { padding: 7px 12px 8px; font-size: 12.5px; }
}
