/* ===========================================================
   Tagda Timer — phone layout

   Linked from index.html with media="(max-width: 640px)", the same query
   js/phone.js asks, so nothing in here can reach a tablet or a desktop: they
   keep the layout they had. Anything a phone-only screen needs that is not
   specific to one tool lives here — the bottom sheet and the move pad today.

   Colours are the theme's tokens and nothing else, so every theme (light ones
   included) carries over. The two derived ones below are the accent as text
   and as a tint; mixing towards --text rather than white keeps accent text
   readable on Paper as well as on Nebula.
   =========================================================== */

:root {
  --accent-text: color-mix(in oklab, var(--accent) 46%, var(--text));
  --accent-tint: color-mix(in oklab, var(--accent) 22%, transparent);
  --phone-gutter: 16px;
}

/* Toasts float over full-screen tools and sheets rather than behind them, and
   in a full-screen tool they sit above the bar at its foot. */
#toasts { z-index: 170; width: calc(100% - 32px); }
body.recon-open #toasts, body.xp1-open #toasts { bottom: calc(96px + env(safe-area-inset-bottom)); }

/* ---------------- bottom sheet ---------------- */
.sheet-scrim {
  position: fixed; inset: 0; z-index: 150;
  background: rgba(0, 0, 0, .55);
}
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 151;
  display: flex; flex-direction: column;
  max-height: calc(100dvh - 24px - env(safe-area-inset-top));
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--surface-2); color: var(--text);
  border-top: 1px solid var(--border);
  border-radius: 28px 28px 0 0;
  font-family: var(--font-ui);
  box-shadow: 0 -18px 40px -18px rgba(0, 0, 0, .6);
  outline: none;
  animation: sheetUp 300ms var(--ease) both;
}
.sheet.closing { animation: sheetDown 220ms cubic-bezier(.4, 0, 1, 1) both; }
@keyframes sheetUp { from { transform: translateY(100%); } }
@keyframes sheetDown { to { transform: translateY(100%); } }
.sheet-grab {
  flex: none; height: 22px; display: grid; place-items: center;
  touch-action: none; cursor: grab;
}
.sheet-grab span { width: 38px; height: 5px; border-radius: 3px; background: var(--text-faint); opacity: .7; }
.sheet-head {
  flex: none; display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 44px; padding: 0 12px 4px 20px; touch-action: none;
}
.sheet-head.bare { min-height: 6px; }
.sheet-title { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -.01em; }
.sheet-done {
  min-width: 44px; height: 44px; padding: 0 10px; border-radius: 22px;
  color: var(--accent-text); font-size: 15px; font-weight: 600;
}
.sheet-body {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: 6px var(--phone-gutter) 18px;
  display: flex; flex-direction: column; gap: 14px;
}
/* The body scrolls; what is in it keeps its own height rather than being
   squeezed (and clipped) to fit. */
.sheet-body > * { flex-shrink: 0; }
.sheet-label { font-size: 13px; font-weight: 600; color: var(--text-dim); margin: 2px 4px -6px; }

/* A grouped list: rows in one card, hairlines between them. */
.sheet-rows {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border); border-radius: 18px; overflow: hidden;
}
.sheet-row {
  display: flex; align-items: center; gap: 12px; width: 100%;
  min-height: 52px; padding: 8px 16px; text-align: left;
  color: var(--text); font-size: 15px;
}
.sheet-row + .sheet-row { border-top: 1px solid var(--border); }
.sheet-row:active { background: color-mix(in srgb, var(--text) 7%, transparent); }
.sheet-row:disabled { opacity: .45; }
.sheet-row.danger { color: var(--danger); }
.sheet-row-ico { flex: none; width: 22px; height: 22px; color: var(--text-dim); }
.sheet-row.danger .sheet-row-ico { color: var(--danger); }
.sheet-row-ico svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.sheet-row-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.sheet-row-label { font-weight: 500; }
.sheet-row-sub {
  font-size: 12.5px; color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sheet-row-sub.mono, .sheet-row .mono { font-family: var(--font-mono); }
.sheet-row-val { flex: none; font-size: 14px; color: var(--text-dim); }

/* Buttons that sit in a sheet's body. */
.sheet-btn {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 50px; padding: 0 18px; border-radius: 15px;
  background: var(--surface); border: 1px solid var(--border);
  color: var(--text); font-size: 15px; font-weight: 600;
}
.sheet-btn.primary { background: var(--accent); border-color: transparent; color: var(--on-accent); font-weight: 700; }
.sheet-field {
  width: 100%; min-height: 50px; padding: 12px 14px; border-radius: 15px;
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
  font-family: var(--font-mono); font-size: 15px; line-height: 1.5; resize: none;
}
.sheet-field:focus { outline: none; border-color: var(--accent); }

/* ---------------- move pad ---------------- */
.mp {
  flex: none;
  padding: 12px 12px max(18px, calc(8px + env(safe-area-inset-bottom)));
  background: var(--surface);
  border-top: 1px solid var(--border);
  border-radius: 26px 26px 0 0;
  display: flex; flex-direction: column; gap: 6px;
  font-family: var(--font-ui);
}
.mp[hidden] { display: none; }
.mp.mp-in { animation: sheetUp 260ms var(--ease) both; }
.mp.mp-nudge { animation: mpNudge 260ms ease both; }
@keyframes mpNudge { 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
.mp-row { display: grid; grid-template-columns: repeat(var(--n, 6), minmax(0, 1fr)); gap: 6px; }
.mp-mods { grid-template-columns: repeat(4, minmax(0, 1fr)) minmax(0, 2fr); }
.mp-key {
  height: 52px; border-radius: 14px;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); color: var(--text);
  font-family: var(--font-mono); font-size: 20px; font-weight: 600;
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 5%, transparent);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation; user-select: none; -webkit-user-select: none;
  transition: transform 80ms ease, background-color 80ms ease;
}
.mp-key:active { transform: scale(.95); background: color-mix(in srgb, var(--text) 14%, var(--surface-2)); }
.mp-key:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.mp-key.slice {
  height: 44px; font-size: 17px; color: var(--text-dim);
  background: color-mix(in srgb, var(--surface-2) 55%, var(--surface));
}
.mp-key.mod:first-child { font-size: 22px; }
.mp-key.back { color: var(--text-dim); }
.mp-key.back svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.mp-key.go {
  background: var(--accent); color: var(--on-accent);
  font-family: var(--font-ui); font-size: 16px; font-weight: 700;
}
.mp-key.go:active { background: color-mix(in srgb, var(--accent) 82%, var(--text)); }

/* With a sheet up, the bottom is the sheet's: a toast goes to the top instead
   of landing on one of its rows. */
body:has(.sheet) #toasts {
  top: calc(12px + env(safe-area-inset-top));
  bottom: auto;
}

/* Rows that say which one is current, and rows that open something. */
.sheet-row.accent .sheet-row-label { color: var(--accent-text); font-weight: 600; }
.sheet-row-check, .sheet-row-chev { flex: none; display: grid; place-items: center; }
.sheet-row-check { color: var(--accent-text); }
.sheet-row-chev { color: var(--text-faint); }
.sheet-row-check svg, .sheet-row-chev svg {
  width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round;
}
.sheet-row-chev svg { width: 17px; height: 17px; stroke-width: 1.7; }

/* ===========================================================
   The phone shell (js/phoneshell.js)

   body.ph is set by phoneshell.js whenever this stylesheet applies, so every
   rule below also says it: the dock, the tabs and the sheets were built for
   this layout and nothing else.
   =========================================================== */

:root {
  --ph-dock-h: 58px;
  --ph-dock-b: calc(12px + env(safe-area-inset-bottom));
  /* What the dock covers, plus a breath: the foot of every tab stops here. */
  --ph-dock-room: calc(var(--ph-dock-h) + var(--ph-dock-b) + 12px);
}

/* The whole screen is the timer, so none of it may be taken for a pan or a
   pull-to-refresh halfway through a hold — the browser cancels the touch when
   it does. Strips and tabs that scroll say so themselves. */
body.ph #app {
  display: flex; flex-direction: column; gap: 0;
  height: 100dvh;
  padding: max(8px, env(safe-area-inset-top)) 0 var(--ph-dock-room);
  touch-action: none;
}
body.ph.sotd #app { padding-bottom: max(12px, env(safe-area-inset-bottom)); }

/* What a phone does not have: the wordmark, the pickers, the menu, the icon
   row (every one of those is in a tab or a sheet now), the floating preview
   (the net in the scramble card), and the rails (the Times tab). */
body.ph .topbar-left, body.ph .topbar-center, body.ph #btn-menu,
body.ph #panel-cube, body.ph #creator-chip, body.ph #dock-bottom,
body.ph #last-replay, body.ph .scramble-label,
body.ph #last-actions [data-act="comment"], body.ph #last-actions [data-act="share"],
body.ph #last-actions [data-act="delete"] { display: none !important; }

/* ---------------- top row: context pill · camera · Daily ---------------- */
body.ph #topbar {
  flex: none; display: flex; flex-wrap: nowrap; align-items: center; gap: 8px;
  min-height: 40px; padding: 0 var(--phone-gutter);
}
body.ph .topbar-right, body.ph .topbar-right:not(.open) {
  display: flex; flex-direction: row; align-items: center; gap: 8px;
  position: static; margin-left: auto; padding: 0; min-width: 0; max-height: none;
  background: none; border: 0; box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none;
}
body.ph .topbar-right > :not(#btn-camera):not(#btn-daily) { display: none !important; }
body.ph .topbar-right > #btn-camera, body.ph .topbar-right > #btn-daily { display: flex; }

.ph-ctx {
  flex: 0 1 auto; min-width: 0;
  display: flex; align-items: center; gap: 8px;
  height: 38px; padding: 0 12px; border-radius: 19px;
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
  font-family: var(--font-ui);
}
.ph-ctx-ico { flex: none; color: var(--accent-text); display: grid; }
.ph-ctx-ico svg, .ph-ctx-chev svg { fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ph-ctx-ico svg { width: 17px; height: 17px; }
.ph-ctx-chev { flex: none; color: var(--text-faint); display: grid; }
.ph-ctx-chev svg { width: 16px; height: 16px; }
.ph-ctx-ev { flex: none; font-size: 14px; font-weight: 600; }
.ph-dot { flex: none; width: 3px; height: 3px; border-radius: 2px; background: var(--text-faint); }
.ph-ctx-ses {
  min-width: 0; font-size: 13.5px; color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

body.ph #btn-camera {
  width: 38px; height: 38px; border-radius: 19px; justify-content: center;
  background: var(--surface); border: 1px solid var(--border); color: var(--text-dim);
}
body.ph #btn-camera svg { width: 18px; height: 18px; }
body.ph #btn-camera.on {
  color: var(--accent-text); background: var(--accent-tint);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}
body.ph #btn-camera .rec-dot { top: 6px; right: 6px; }

body.ph #btn-daily {
  height: 38px; padding: 0 13px 0 11px; gap: 6px; border-radius: 19px;
  color: var(--gold);
  background: color-mix(in srgb, var(--gold) 10%, transparent);
  border-color: color-mix(in srgb, var(--gold) 24%, transparent);
}
body.ph #btn-daily .sotd-glyph, body.ph #btn-daily .sotd-glyph svg { width: 16px; height: 16px; }
body.ph #btn-daily .sotd-label { display: none; }
/* Gold as text, pulled towards the theme's own text colour so it still reads
   on a light theme. */
.ph-daily-lbl { font-size: 13px; font-weight: 600; color: color-mix(in oklab, var(--gold) 72%, var(--text)); }
/* Done for today: the quiet outline main.js has always given it, a circle here. */
body.ph #btn-daily.done {
  width: 38px; padding: 0; justify-content: center;
  color: var(--text-faint); background: var(--surface); border-color: var(--border);
}
body.ph #btn-daily.done .ph-daily-lbl { display: none; }

/* ---------------- the scramble ----------------
   Floating on the background, as it was before the shell: no card, just the
   notation, small enough that a 3x3 scramble is two lines, with the tools and
   the net in one short row under it. The shadow is the theme's own background
   colour, so the letters keep an edge over a busy wallpaper on dark and light
   themes alike. */
body.ph #scramble-zone {
  flex: none; align-items: stretch; gap: 6px;
  margin: 8px var(--phone-gutter) 0; padding: 0;
  background: none; border: 0; border-radius: 0;
}
body.ph #scramble-wrap {
  width: auto; padding: 0;
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
  column-gap: 8px; row-gap: 4px;
}
body.ph #scramble-text {
  grid-column: 1 / -1;
  padding: 0 2px; border: 0; border-radius: 0; background: none;
  font-size: calc(15.5px * var(--scramble-scale));
  font-weight: 600; line-height: 1.5; word-spacing: .08em; letter-spacing: 0;
  text-align: center; text-wrap: balance; white-space: pre-wrap;
  text-shadow: 0 1px 3px color-mix(in srgb, var(--bg) 85%, transparent), 0 0 10px color-mix(in srgb, var(--bg) 55%, transparent);
}
body.ph #scramble-text:hover { background: none; }
body.ph #scramble-text.long { font-size: calc(13px * var(--scramble-scale)); }
body.ph #scramble-text.multiline { font-size: calc(12px * var(--scramble-scale)); line-height: 1.4; text-align: left; text-wrap: initial; }
body.ph #scramble-text.race-hold { font-family: var(--font-ui); font-size: 14px; color: var(--text-dim); }
body.ph #scramble-tools {
  grid-column: 1; justify-self: start;
  position: static; transform: none; opacity: 1;
  display: flex; gap: 0; margin: 0 0 0 -6px; color: var(--text-dim);
}
/* Previous, next, copy, your own: the order the card reads them in. */
body.ph #btn-prev-scramble { order: 1; }
body.ph #btn-next-scramble { order: 2; }
body.ph #btn-copy-scramble { order: 3; }
body.ph #btn-custom-scramble { order: 4; }
body.ph #scramble-tools .ghost-btn {
  width: 40px; height: 40px; padding: 0; border: 0; border-radius: 20px; background: none;
  display: grid; place-items: center; color: var(--text-dim);
}
body.ph #scramble-tools .ghost-btn svg { width: 19px; height: 19px; stroke-width: 1.7; }
body.ph #scramble-tools .ghost-btn:active { background: color-mix(in srgb, var(--text) 8%, transparent); }

.ph-net {
  grid-column: 2; justify-self: end;
  padding: 4px; border-radius: 10px;
  background: color-mix(in srgb, var(--bg) 70%, transparent); border: 1px solid var(--border);
}
.ph-net-host { width: 60px; height: 45px; pointer-events: none; }
.ph-net-host twisty-player { width: 100%; height: 100%; }
body.no-cube .ph-net { display: none; }
body.sotd .ph-net { grid-column: 1 / -1; justify-self: center; }

/* The lines that hang under the scramble on a phone are the same ones the
   desktop has; they only get tighter. */
body.ph #goal-line, body.ph #now-playing, body.ph #custom-bar, body.ph #case-label { margin: 0; align-self: center; }
body.ph #bld-zone, body.ph #phase-zone, body.ph #learn-bar { margin-top: 0; }

/* ---------------- the clock ---------------- */
body.ph #stage {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; gap: 0;
  padding: 0 var(--phone-gutter);
}
/* Centred by two spacers that shrink to nothing, not by `justify-content:
   safe center`: iOS Safari ignored the `safe` and centred anyway, so a block
   too tall for the space (the clock on an iPhone 8, a Fewest Moves attempt, a
   long multiphase readout) spilled upwards over the scramble. Spacers can
   only ever push it down from the top of its box. */
body.ph #timer-zone { flex: 1 1 auto; min-height: 0; justify-content: flex-start; }
body.ph #timer-zone::before, body.ph #timer-zone::after { content: ''; flex: 1 1 0; min-height: 0; }
body.ph #sidebar { display: none; }
/* The right rail holds the race panel while a room is open (it docks itself
   across the foot of the screen); the figures are the Times tab's. */
body.ph #sidebar-right { flex: none; height: 0; min-height: 0; overflow: visible; }
body.ph #panel-stats { display: none !important; }
body.ph #panel-race {
  left: var(--phone-gutter); right: var(--phone-gutter); bottom: var(--ph-dock-room);
  border-radius: 20px; border-bottom: 1px solid var(--border);
  max-height: 52vh; padding-bottom: 10px;
}
body.ph.sotd #panel-race, body.ph:is(.focus, .inspecting, .timing) #panel-race { bottom: max(12px, env(safe-area-inset-bottom)); }

body.ph #timer-core {
  position: relative; left: auto; top: auto; transform: none;
  gap: 0;
}
body.ph #timer-display {
  order: 1;
  font-family: var(--font-mono);
  /* 85px on a 390px phone, never more than an eighth of the screen's height,
     and never wider than the screen however many characters the time has. */
  font-size: min(calc(var(--timer-size) * 1.45), calc((100vw - 2 * var(--phone-gutter)) / (var(--ph-chars, 5) * .58)), 12.5vh);
  letter-spacing: -.055em; line-height: 1;
}
body.ph #timer-avgs {
  order: 2;
  position: static; transform: none; width: auto;
  display: flex; align-items: stretch; column-gap: 18px; row-gap: 4px; margin-top: 10px;
}
body.ph #timer-avgs[hidden] { display: none; }
body.ph #timer-avgs > span:not(.sep) { display: flex; flex-direction: column; align-items: center; gap: 1px; }
body.ph #timer-avgs b {
  display: flex; align-items: center; gap: 6px;
  font-family: var(--font-ui); font-size: 11.5px; font-weight: 600; letter-spacing: 0; text-transform: none;
  color: var(--text-dim); line-height: 17px;
}
body.ph #timer-avgs > span > i {
  font-size: 18px; font-weight: 600; letter-spacing: -.01em; line-height: 1.15;
}
body.ph #timer-avgs.no-avg > span, body.ph #timer-avgs.solo > :is(.a12, .sep) { display: none; }
body.ph #timer-avgs #timer-bpa i { font-size: 13px; }
body.ph #timer-bpa b { display: inline; color: var(--text-faint); }
body.ph #timer-avgs i.ph-is-best { color: var(--accent-2); }
body.ph #timer-avgs .sep { width: 1px; height: auto; align-self: stretch; background: var(--border); }
.ph-best {
  font-family: var(--font-ui); font-size: 10.5px; font-weight: 600; line-height: 17px;
  padding: 0 6px; border-radius: 6px;
  color: var(--accent-2); background: color-mix(in srgb, var(--accent-2) 14%, transparent);
}
.ph-best[hidden] { display: none; }
body.ph #timer-bpa { grid-column: auto; margin-top: 2px; }

/* How it compared with the last one: above the digits, in a band kept for it
   whether or not it is showing, so the clock does not move when it lands. */
body.ph #timer-core { padding-top: 26px; }
body.ph #last-row {
  position: absolute; left: 0; right: 0; top: 0; height: 22px;
  display: flex; justify-content: center; align-items: center; pointer-events: none;
}
body.ph #last-delta { font-size: 13px; }

body.ph #last-actions {
  order: 3;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 6px;
  max-width: none; margin-top: 14px;
}
body.ph #last-actions .ph-pill, body.ph #last-actions .ghost-btn.ph-pill {
  display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 12px; border-radius: 16px;
  background: var(--surface); border: 1px solid var(--border);
  font-family: var(--font-ui); font-size: 13px; font-weight: 600; color: var(--text);
}
body.ph #last-actions .ph-pill[hidden] { display: none; }
body.ph #last-actions .ph-pill svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
body.ph #last-actions .ph-pill svg .fill, body.ph .ph-tab-ico .fill, .ph-sheet-ico .fill { fill: currentColor; stroke: none; }
body.ph #last-actions [aria-pressed="true"] {
  color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, transparent);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
}

body.ph #timer-hint {
  order: 4; margin-top: 12px; height: auto; max-width: none;
  font-size: 12.5px; letter-spacing: 0; color: var(--text-faint);
}
body.ph #phase-readout, body.ph #phase-live, body.ph #relay-now,
body.ph #pace-ghost, body.ph #hold-bar, body.ph #manual-entry, body.ph #stackmat-bar { order: 5; margin-top: 14px; }
body.ph #pace-ghost { width: min(320px, 80vw); }
/* Fewest Moves puts its hour and its solution where the timer's buttons go. */
body.ph .fmc-zone { order: 3; margin-top: 20px; width: 100%; }
body.ph.fmc-attempting :is(.ph-recent, #last-actions) { display: none; }
body.ph.fmc-attempting #app { padding-bottom: max(12px, env(safe-area-inset-bottom)); }
body.ph #manual-entry input { font-size: 16px; }

/* ---------------- swipe to edit (js/swipe-edit.js) ----------------
   Mid-swipe the digits follow the finger and the four edits sit round them,
   on a dashed ring; the picked one grows and takes its colour, and the line
   under where the averages were says what letting go will do. Everything else
   steps back so the gesture is the one thing on the screen. The places are
   measured from the digits when the swipe starts (--sw-*). */
.ph-swipe {
  position: absolute; inset: 0; z-index: 3; pointer-events: none;
  opacity: 0; visibility: hidden;
  transition: opacity 140ms var(--ease), visibility 0s linear 140ms;
}
body.ph.swiping .ph-swipe { opacity: 1; visibility: visible; transition: opacity 140ms var(--ease); }
.ph-sw-ring {
  position: absolute; left: var(--sw-cx); top: var(--sw-cy);
  width: var(--sw-ring, 300px); height: var(--sw-ring, 300px); translate: -50% -50%;
  border-radius: 50%; border: 1px dashed var(--border); opacity: .8;
}
.ph-sw-dir {
  position: absolute; display: flex; flex-direction: column; align-items: center; gap: 2px;
  /* --text-dim, not the mockup's --text-faint: faint sank into Paper's cells. */
  font: 700 13px/16px var(--font-mono); color: var(--text-dim);
  text-shadow: 0 1px 3px color-mix(in srgb, var(--bg) 85%, transparent);
  transition: scale 140ms var(--ease), color 140ms var(--ease);
}
.ph-sw-dir b { font-size: 18px; line-height: 20px; font-weight: 700; }
.ph-sw-dir[data-dir="up"] { left: var(--sw-cx); top: var(--sw-top); translate: -50% calc(-100% - var(--sw-gap)); }
.ph-sw-dir[data-dir="down"] { left: var(--sw-cx); top: var(--sw-bot); translate: -50% var(--sw-gap); }
.ph-sw-dir:is([data-dir="left"], [data-dir="right"]) { top: var(--sw-cy); width: 56px; translate: 0 -50%; }
.ph-sw-dir[data-dir="left"] { left: 4px; }
.ph-sw-dir[data-dir="right"] { right: 4px; }
/* A time too wide for labels beside it: ← and → on the DNF label's row. */
.ph-swipe.low .ph-sw-dir:is([data-dir="left"], [data-dir="right"]) { top: var(--sw-bot); translate: 0 var(--sw-gap); }
.ph-sw-dir.on { scale: 1.15; }
.ph-sw-dir.on[data-tone="warn"], .ph-sw-hint[data-tone="warn"] { color: var(--warn); }
.ph-sw-dir.on[data-tone="danger"], .ph-sw-hint[data-tone="danger"] { color: var(--danger); }
.ph-sw-dir.on[data-tone="accent-2"], .ph-sw-hint[data-tone="accent-2"] { color: var(--accent-2); }
.ph-sw-hint, .ph-sw-sub {
  position: absolute; left: var(--phone-gutter); right: var(--phone-gutter); margin: 0;
  text-align: center; text-shadow: 0 1px 3px color-mix(in srgb, var(--bg) 85%, transparent);
}
.ph-sw-hint { top: var(--sw-hint); font: 600 15px/20px var(--font-ui); color: var(--text-dim); }
.ph-sw-sub { top: calc(var(--sw-hint) + 26px); font: 500 13px/18px var(--font-ui); color: var(--text-faint); }
.ph-sw-sub[hidden] { display: none; }
/* The averages, the pills and the hint give their room to the DNF label and
   the line under it; the top of the screen dims. */
body.ph.swiping :is(#timer-avgs, #last-actions, #timer-hint, #last-row, .pb-marquee) { opacity: 0; transition: opacity 140ms var(--ease); }
body.ph.swiping :is(#topbar, #scramble-zone) { opacity: .25; transition: opacity 140ms var(--ease); }

/* ---------------- the recent strip ---------------- */
.ph-recent { flex: none; padding: 6px 0 0 var(--phone-gutter); }
.ph-recent-head {
  display: flex; justify-content: space-between; align-items: center;
  padding-right: 20px; margin-bottom: 2px; min-height: 20px;
}
.ph-lbl { font-size: 12.5px; font-weight: 600; color: var(--text-dim); }
.ph-all {
  margin: -11px -8px; padding: 11px 8px; min-height: 44px;
  font-size: 12.5px; font-weight: 600; color: var(--accent-text);
}
.ph-all[hidden] { display: none; }
.ph-chips {
  display: flex; gap: 8px; overflow-x: auto; overscroll-behavior-x: contain;
  padding: 4px var(--phone-gutter) 2px 0; scrollbar-width: none;
  touch-action: pan-x;
}
.ph-chips::-webkit-scrollbar { display: none; }
.ph-chip {
  flex: none; display: flex; align-items: center;
  height: 38px; padding: 0 12px; border-radius: 12px;
  background: var(--surface); border: 1px solid var(--border);
  font-family: var(--font-mono); font-size: 14px; font-weight: 600; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.ph-chip.latest { border-color: var(--accent); }
.ph-chip.best { color: var(--accent-2); }
.ph-chip.dnf { color: var(--danger); }
.ph-chip:active { background: var(--surface-2); }
.ph-chips-empty { display: flex; align-items: center; height: 38px; font-size: 13.5px; color: var(--text-faint); }

/* ---------------- the dock ---------------- */
.ph-dock {
  position: fixed; z-index: 40;
  left: var(--phone-gutter); right: var(--phone-gutter); bottom: var(--ph-dock-b);
  height: var(--ph-dock-h); padding: 5px; border-radius: 22px;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 4px;
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: 0 18px 40px -10px rgba(0, 0, 0, .7);
  font-family: var(--font-ui);
  touch-action: none;
}
.ph-tab {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-width: 0; border-radius: 17px; color: var(--text-dim);
  -webkit-tap-highlight-color: transparent;
}
.ph-tab.on { background: var(--accent-tint); color: var(--accent-text); }
.ph-tab-ico { display: grid; }
.ph-tab-ico svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ph-tab.on .ph-tab-ico svg { stroke-width: 1.9; }
.ph-tab-lbl { font-size: 10.5px; font-weight: 600; letter-spacing: .01em; }
.ph-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* An attempt is nothing but the clock: from the press, through inspection and
   the solve, until it stops. The same for the tools that are a screen of their
   own, and for the Scramble of the Day, which is one attempt and nothing else. */
body.ph:is(.focus, .inspecting, .holding, .armed, .timing, .sotd, .fmc-attempting, .recon-open, .xp1-open) .ph-dock {
  transform: translateY(calc(100% + var(--ph-dock-b) + 20px));
  visibility: hidden;
}
.ph-dock { transition: transform 220ms var(--ease), visibility 0s linear 0s; }
body.ph:is(.focus, .inspecting, .holding, .armed, .timing, .sotd, .fmc-attempting, .recon-open, .xp1-open) .ph-dock {
  transition: transform 220ms var(--ease), visibility 0s linear 220ms;
}
body.ph:is(.focus, .inspecting, .holding, .armed, .timing) :is(#topbar, #scramble-zone, .ph-recent) {
  opacity: 0; pointer-events: none;
  transition: opacity 160ms var(--ease);
}
/* Which puzzle of a relay you are on is the one thing the clock cannot say. */
body.ph.relay:is(.focus, .inspecting, .holding, .armed, .timing) #scramble-zone { opacity: 1; background: none; border-color: transparent; }
body.ph.relay:is(.focus, .inspecting, .holding, .armed, .timing) #scramble-zone > :not(#relay-rail) { opacity: 0; }
body.ph:is(.sotd) .ph-recent { display: none; }
/* The phone defaults must not restore practice controls inside the daily attempt. */
body.ph.sotd :is(#scramble-tools, #timer-avgs, #last-delta) { display: none; }
body.ph:has(#panel-race:not([hidden])) .ph-recent { visibility: hidden; }

/* A toast stands above the dock, never on it: the "New personal best!" one
   stays up until the next attempt, and on the dock it took the taps meant for
   Times and Train. (Full-screen tools and open sheets place toasts themselves,
   further up this file.) */
body.ph:not(.recon-open, .xp1-open):not(:has(.sheet)) #toasts { bottom: calc(var(--ph-dock-room) + 4px); }
/* The support card must leave the tab buttons reachable, just like toasts. */
body.ph .coffee-nudge { right: var(--phone-gutter); bottom: calc(var(--ph-dock-room) + 4px); }
/* Save/undo messages must remain readable while the support card is open. */
body.ph:not(.recon-open, .xp1-open):not(:has(.sheet)):has(.coffee-nudge) #toasts {
  top: calc(12px + env(safe-area-inset-top)); bottom: auto;
}
/* A toast with nothing to press is something to read, not a lid: taps go
   through it to whatever it is lying over. */
body.ph .toast:not(:has(button, a)) { pointer-events: none; }
/* The new-best ticker runs above the digits, in the band the "vs last" chip
   uses; for its five seconds it has the band to itself. */
body.ph #timer-core:has(.pb-marquee) #last-delta { visibility: hidden; }

/* ---------------- inspection ---------------- */
body.ph #inspect-readout:not([hidden]) {
  position: fixed; inset: 0; transform: none;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0;
  pointer-events: none;
}
body.ph #inspect-hint {
  order: -1;
  font-family: var(--font-ui); font-size: 14px; font-weight: 600;
  letter-spacing: 0; text-transform: none;
  color: color-mix(in oklab, var(--warn) 62%, var(--text-dim));
}
body.ph #inspect-hint::first-letter { text-transform: uppercase; }
body.ph #inspect-num {
  font-family: var(--font-mono); font-weight: 700;
  font-size: min(168px, 40vw); letter-spacing: -.05em; line-height: 1;
  margin-top: 4px; text-shadow: none;
}
.ph-insp-left { font-size: 15px; color: color-mix(in oklab, var(--warn) 40%, var(--text)); margin-top: 4px; }
.ph-insp-rule { font-size: 13px; color: color-mix(in oklab, var(--warn) 35%, var(--text-dim)); margin-top: 18px; }
#inspect-readout.ph-pen .ph-insp-left { visibility: hidden; }
.ph-insp-foot {
  position: fixed; left: 0; right: 0; bottom: max(64px, calc(40px + env(safe-area-inset-bottom)));
  text-align: center; padding: 0 var(--phone-gutter);
}
.ph-insp-hold { font-size: 15.5px; font-weight: 600; color: color-mix(in oklab, var(--warn) 25%, var(--text)); }
.ph-insp-gone { font-size: 13px; color: color-mix(in oklab, var(--warn) 35%, var(--text-dim)); margin-top: 6px; }
body.ph:is(.holding, .armed) .ph-insp-hold { color: var(--t-ready); }
body.ph #inspect-cancel {
  position: fixed; top: max(12px, calc(env(safe-area-inset-top) + 4px)); right: 12px; left: auto;
  transform: none; margin: 0;
  width: 44px; height: 44px; padding: 0; border: 0; border-radius: 22px; background: none;
  display: grid; place-items: center; font-size: 0;
  color: color-mix(in oklab, var(--warn) 55%, var(--text-dim));
  pointer-events: auto;
}
body.ph #inspect-cancel .ph-x { display: grid; }
body.ph #inspect-cancel .ph-x svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; }
/* The screen warms with the countdown, as the shader behind it does. */
body.ph.inspecting::before {
  content: ''; position: fixed; inset: 0; z-index: 1; pointer-events: none;
  background: color-mix(in srgb, var(--ph-insp, var(--accent-2)) 7%, transparent);
}
body.ph[data-insp-band="warm"] { --ph-insp: var(--warn); }
body.ph[data-insp-band="hot"] { --ph-insp: var(--danger); }
body.ph #inspect-ring-rect { stroke-width: 5; }

/* ---------------- Times, Train, More ---------------- */
.ph-screen {
  /* Ends just above the dock, so nothing scrolls into the gap beneath it. */
  position: fixed; inset: 0 0 calc(var(--ph-dock-room) - 6px) 0; z-index: 20;
  display: flex; flex-direction: column; gap: 14px;
  padding: max(12px, env(safe-area-inset-top)) var(--phone-gutter) 16px;
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--bg); color: var(--text); font-family: var(--font-ui);
  touch-action: pan-y;
}
.ph-screen[hidden] { display: none; }
/* ...and the strip the dock floats in is the tab's background, not the timer
   showing through underneath. */
body.ph:is([data-tab="times"], [data-tab="train"], [data-tab="more"])::after {
  content: ''; position: fixed; left: 0; right: 0; bottom: 0; z-index: 39;
  height: calc(var(--ph-dock-room) - 6px); background: var(--bg); pointer-events: none;
}
.ph-screen > * { flex-shrink: 0; }
.ph-screen-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 44px; padding-left: 4px; }
.ph-screen-head h1 { margin: 0; font-size: 30px; font-weight: 700; letter-spacing: -.025em; }
.ph-head-r { display: flex; align-items: center; gap: 2px; min-width: 0; }
.ph-ctx.small { height: 36px; gap: 6px; padding: 0 10px 0 12px; border-radius: 18px; font-size: 13.5px; font-weight: 600; }
.ph-ctx.small .ph-ctx-ses { color: var(--text); font-size: 13.5px; }
.ph-icon-btn { flex: none; width: 44px; height: 44px; border-radius: 22px; display: grid; place-items: center; color: var(--text-dim); }
.ph-icon-btn svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ph-icon-btn svg .fill { fill: currentColor; stroke: none; }

/* ---------------- Times ---------------- */
/* The tab itself does not scroll: the list under it does, and it is laid over
   the space the slot leaves, measured once and again on every resize. */
#ph-times { overflow: hidden; }
.ph-cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.ph-card { min-width: 0; padding: 12px 14px; border-radius: 18px; background: var(--surface); border: 1px solid var(--border); }
.ph-card-k { display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; color: var(--text-dim); }
.ph-card-v {
  margin-top: 4px; font-family: var(--font-mono); font-size: 27px; font-weight: 600; letter-spacing: -.02em; line-height: 1.15;
  font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ph-card.is-best .ph-card-v { color: var(--accent-2); }
.ph-card-sub { margin-top: 1px; font-size: 12px; color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.ph-trend { padding: 12px 14px 14px; border-radius: 18px; background: var(--surface); border: 1px solid var(--border); }
.ph-trend-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 12px; }
.ph-legend { display: flex; align-items: center; gap: 12px; font-size: 12px; color: var(--text-dim); }
.ph-lg { display: flex; align-items: center; gap: 5px; }
.ph-lg-line { width: 12px; height: 2px; border-radius: 1px; background: var(--accent-2); }
.ph-lg-dot { width: 5px; height: 5px; border-radius: 3px; background: var(--text-faint); }
.ph-charts { margin: -14px -8px; padding: 14px 8px; font-size: 12px; font-weight: 600; color: var(--accent-text); }
.ph-trend-svg { display: block; width: 100%; height: 84px; overflow: visible; }
.ph-trend-svg[hidden], .ph-trend-empty[hidden] { display: none; }
.dt-grid { stroke: var(--border); stroke-dasharray: 3 4; }
.dt-tick { fill: var(--text-faint); font-family: var(--font-mono); font-size: 10px; }
.dt-ao { fill: none; stroke: var(--accent-2); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.dt-dot { fill: var(--text-faint); }
.dt-pb { fill: none; stroke: var(--accent-2); stroke-width: 2; }
.dt-dnf { fill: none; stroke: var(--danger); stroke-width: 1.6; stroke-linecap: round; }
.ph-trend-empty { margin: 0; padding: 22px 0; text-align: center; font-size: 13px; color: var(--text-faint); }
.ph-times-slot { flex: 1 1 auto; min-height: 120px; }

/* The desktop's times list, laid over the slot, and set the way the tab draws
   it: a plain list of 50px rows under sentence-case headings. Sorting, the
   column pencils and the average cells (which open their solves) all work as
   they do on the desktop. */
body.ph[data-tab="times"] #sidebar {
  display: flex !important;
  position: fixed; z-index: 21;
  top: var(--ph-slot-top, 300px); bottom: var(--ph-dock-room);
  left: 8px; right: 8px;
  height: auto; padding: 0;
}
body.ph[data-tab="times"] #panel-times { display: flex !important; flex: 1 1 auto; min-height: 0; }
body.ph #panel-times {
  --pad: 0px; --idx-col: 44px; --ao-col: calc(70px * var(--times-scale)); --hist-gap: 6px;
  gap: 0; padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none;
  backdrop-filter: none; -webkit-backdrop-filter: none;
}
body.ph #panel-times > :is(.panel-head, .times-foot, .tile-grip),
body.ph #sidebar > :not(#panel-times) { display: none !important; }
body.ph #panel-times .hist-cols {
  min-height: 0; margin: 0 0 4px; padding: 6px 12px 4px; border: 0;
  font-family: var(--font-ui); font-size: 12px; font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--text-dim);
}
body.ph #panel-times .hist-cols[hidden] { display: none; }
body.ph .competition-set-box .competition-set-attempt { grid-template-columns: 24px minmax(0, 1fr); height: 44px; padding: 0 6px; }
body.ph .competition-set-box .competition-set-attempt .t { font-size: calc(17px * var(--times-scale)); }
body.ph .competition-set-heading { padding: 13px 12px; }
body.ph .competition-set-title { font-size: 13px; }
body.ph #panel-times .hist-cols > span:first-child::before { content: '#'; }
body.ph #panel-times .hist-cols > span:last-child:empty { display: none; }
body.ph #panel-times .hist-cols [data-sort].sorted { color: var(--accent-text); }
body.ph #panel-times .col-edit { width: 14px; font-size: 11px; opacity: .75; }
body.ph #hist-list { margin: 0; padding: 0; gap: 0; touch-action: pan-y; }
body.ph .solve-chip {
  flex: none; height: 50px; padding: 0 12px; border: 0; border-radius: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
  background: none; color: var(--text);
  font-size: calc(17px * var(--times-scale)); font-weight: 600;
  -webkit-tap-highlight-color: transparent;
}
body.ph .solve-chip:hover { background: none; border-color: color-mix(in srgb, var(--border) 60%, transparent); }
body.ph .solve-chip:active { background: color-mix(in srgb, var(--text) 6%, transparent); }
body.ph .solve-chip .idx { text-align: left; font-size: 13px; font-weight: 500; color: var(--text-faint); }
body.ph .solve-chip .avg { font-size: calc(14px * var(--times-scale)); font-weight: 500; color: var(--text-dim); padding: 1px 0; }
body.ph .solve-chip .avg.best { color: var(--accent-2); background: none; font-weight: 600; }
/* Best teal, DNF red, +2 written with its "+" and nothing else. */
body.ph .solve-chip:is(.pb, .plus2) { color: var(--text); background: none; }
body.ph .solve-chip.pb .t { color: var(--accent-2); }
body.ph .solve-chip.dnf .t { color: var(--danger); text-decoration: none; }
body.ph .hist-end { padding: 14px 0 8px; font-size: 12px; }

/* ---------------- Train ---------------- */
.ph-tools, .ph-minis { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.ph-minis { margin-top: -6px; }
.ph-tool {
  display: flex; flex-direction: column; align-items: flex-start; min-width: 0;
  padding: 14px; border-radius: 20px; text-align: left;
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
}
.ph-tool-ico { width: 42px; height: 42px; border-radius: 13px; display: grid; place-items: center; background: var(--accent-tint); color: var(--accent-text); }
.ph-tool-t { margin-top: 12px; font-size: 16px; font-weight: 600; }
.ph-tool-s { margin-top: 3px; font-size: 13px; line-height: 1.4; color: var(--text-dim); }
.ph-mini {
  display: flex; align-items: center; gap: 10px; min-width: 0; min-height: 60px;
  padding: 12px; border-radius: 18px; text-align: left;
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
}
.ph-mini.gold { background: color-mix(in srgb, var(--gold) 7%, var(--surface)); border-color: color-mix(in srgb, var(--gold) 26%, transparent); }
.ph-mini-ico { flex: none; display: grid; color: var(--text-dim); }
.ph-mini.gold .ph-mini-ico { color: color-mix(in oklab, var(--gold) 80%, var(--text)); }
.ph-mini-txt { min-width: 0; }
.ph-mini-t { display: block; font-size: 14px; font-weight: 600; line-height: 1.25; }
.ph-mini-s { display: block; margin-top: 2px; font-size: 12px; color: var(--text-dim); }
:is(.ph-tool-ico, .ph-mini-ico, .ph-row-ico, .ph-sync-pic, .ph-link) svg {
  width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
}
.ph-sec-head { display: flex; align-items: center; justify-content: space-between; margin: 6px 0 -8px 4px; }
.ph-sec { margin: 0; font-size: 13px; font-weight: 600; color: var(--text-dim); }
.ph-link.accent { color: var(--accent-text); text-decoration: none; font-size: 13px; }
.ph-link.accent svg { width: 18px; height: 18px; }

.ph-group { display: flex; flex-direction: column; overflow: hidden; border-radius: 20px; background: var(--surface); border: 1px solid var(--border); }
.ph-row { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 54px; padding: 8px 14px; text-align: left; color: var(--text); }
.ph-row + .ph-row { border-top: 1px solid var(--border); }
.ph-row:active { background: color-mix(in srgb, var(--text) 6%, transparent); }
#ph-train .ph-row { min-height: 62px; padding: 8px 16px; }
.ph-row-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.ph-row-txt .ph-row-t { font-size: 15.5px; font-weight: 600; }
.ph-row-s { margin-top: 2px; font-size: 12.5px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ph-row.current .ph-row-t { color: var(--accent-text); }
.ph-due { flex: none; padding: 3px 7px; border-radius: 7px; font-size: 11.5px; font-weight: 700; color: var(--warn); background: color-mix(in srgb, var(--warn) 13%, transparent); }
.ph-prog { flex: none; width: 76px; display: flex; flex-direction: column; align-items: flex-end; gap: 5px; }
.ph-prog-t { font-size: 12px; color: var(--text-dim); white-space: nowrap; }
.ph-prog-t.none { color: var(--text-faint); }
.ph-prog-bar { width: 76px; height: 4px; border-radius: 2px; overflow: hidden; background: var(--border); }
.ph-prog-bar i { display: block; height: 4px; border-radius: 2px; background: var(--accent-2); }
.ph-note.pad { padding: 16px; }

/* ---------------- More ---------------- */
/* Wraps rather than squeezes: a long sign-in label (Spanish, at 360px) drops
   below the words instead of crushing them into a column. */
.ph-sync { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 14px; padding: 16px; border-radius: 20px; background: var(--surface); border: 1px solid var(--border); }
.ph-sync:has(.ph-sync-in) { padding: 0; }
.ph-sync-in { display: flex; align-items: center; gap: 14px; width: 100%; padding: 16px; text-align: left; color: var(--text); }
.ph-sync-pic {
  flex: none; width: 46px; height: 46px; border-radius: 23px; overflow: hidden;
  display: grid; place-items: center; background: var(--surface-2); color: var(--text-dim);
}
.ph-sync-pic img { width: 100%; height: 100%; object-fit: cover; }
.ph-sync-pic .account-initial { font-size: 18px; font-weight: 700; color: var(--text); }
.ph-sync-txt { flex: 1 1 150px; min-width: 0; display: flex; flex-direction: column; }
.ph-sync-t { font-size: 15.5px; font-weight: 600; overflow-wrap: anywhere; }
.ph-sync-in .ph-sync-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ph-sync-s { margin-top: 2px; font-size: 13px; line-height: 1.35; color: var(--text-dim); overflow-wrap: anywhere; }
.ph-sync-btn {
  flex: none; position: relative; margin-left: auto; height: 38px; padding: 0 16px; border-radius: 19px;
  background: var(--accent); color: var(--on-accent); font-size: 14px; font-weight: 700;
}
.ph-sync-btn::after { content: ''; position: absolute; inset: -3px 0; }
.ph-more { display: flex; flex-direction: column; gap: 12px; }
.ph-row-ico { flex: none; width: 32px; height: 32px; border-radius: 10px; display: grid; place-items: center; background: var(--surface-2); color: var(--text-dim); }
.ph-row-ico svg { width: 19px; height: 19px; }
.ph-row > .ph-row-t { flex: 1; min-width: 0; font-size: 15px; font-weight: 500; }
.ph-row-v { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: 14px; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ph-row-vv { display: flex; align-items: center; gap: 6px; }
.ph-swatches { display: flex; gap: 3px; }
.ph-swatches i { width: 12px; height: 12px; border-radius: 6px; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text) 16%, transparent); }

/* A short phone keeps all of the Times tab, a little tighter, so the list
   under it still shows several rows. */
@media (max-height: 780px) {
  #ph-times { gap: 10px; }
  .ph-card { padding: 9px 12px; }
  .ph-card-v { font-size: 23px; margin-top: 2px; }
  .ph-trend { padding: 10px 12px 10px; }
  .ph-trend-head { margin-bottom: 6px; }
  .ph-trend-svg { height: 60px; }
}

/* ---------------- sheets the shell opens ---------------- */
.ph-ev-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.ph-ev {
  height: 50px; border-radius: 14px; min-width: 0;
  background: var(--surface); border: 1px solid var(--border);
  font-size: 14.5px; font-weight: 600; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 4px;
}
.ph-ev.on { background: var(--accent-tint); border: 1.5px solid var(--accent); font-weight: 700; }
.ph-ev:active { background: var(--surface-2); }

.ph-sv .sheet-body { gap: 12px; }
.ph-sv-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.ph-sv-when, .ph-sv-avgs { font-size: 13px; color: var(--text-dim); }
.ph-sv-avgs { margin-top: 6px; white-space: pre; }
.ph-sv-avgs b { font-family: var(--font-mono); font-weight: 600; color: var(--text); }
.ph-sv-time { font-family: var(--font-mono); font-size: 50px; font-weight: 700; letter-spacing: -.045em; line-height: 1.05; margin-top: 4px; }
.ph-sv-time.dnf { color: var(--danger); }
.ph-sv-close {
  flex: none; width: 44px; height: 44px; border-radius: 22px; display: grid; place-items: center;
  background: var(--surface); color: var(--text-dim);
}
.ph-sv-close svg, .ph-btn svg, .ph-link svg, .ph-seg-btn svg {
  width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
}
.ph-sv-close svg { width: 20px; height: 20px; }
.ph-seg {
  /* Equal thirds, unless a word needs more ("Sin penalización" at 360px). */
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(max-content, 1fr); gap: 4px;
  padding: 4px; border-radius: 14px; background: var(--surface);
}
.ph-seg-btn {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 44px; padding: 0 10px; border-radius: 11px;
  font-size: 14px; font-weight: 600; color: var(--text-dim); white-space: nowrap;
}
.ph-seg-btn.on { background: var(--surface-2); color: var(--text); font-weight: 700; box-shadow: 0 1px 0 color-mix(in srgb, var(--text) 6%, transparent) inset; }
.ph-sv-scr {
  display: flex; gap: 12px; align-items: center;
  padding: 12px 14px; border-radius: 16px; background: var(--surface);
}
.ph-sv-scr p, .ph-sv-block p {
  margin: 0; flex: 1; min-width: 0;
  font-family: var(--font-mono); font-size: 13.5px; line-height: 1.55; word-spacing: .1em;
  color: var(--text); overflow-wrap: anywhere;
}
.ph-sv-net { flex: none; width: 68px; height: 51px; }
.ph-sv-note {
  width: 100%; min-height: 46px; padding: 12px 14px; border-radius: 14px;
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
  font-family: var(--font-ui); font-size: 16px; line-height: 1.35; resize: none; field-sizing: content;
}
.ph-sv-note:focus { outline: none; border-color: var(--accent); }
.ph-sv-main { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 8px; }
.ph-btn {
  display: flex; align-items: center; justify-content: center; gap: 8px; min-width: 0;
  height: 52px; padding: 0 12px; border-radius: 16px;
  background: var(--surface); color: var(--text); font-size: 15px; font-weight: 600;
}
.ph-btn.primary { background: var(--accent); color: var(--on-accent); font-weight: 700; }
.ph-btn span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ph-sv-block { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px; border-radius: 16px; background: var(--surface); }
.ph-sv-foot { display: flex; justify-content: space-between; gap: 12px; margin-top: -4px; }
.ph-link {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 44px; padding: 0 4px;
  font-size: 14px; font-weight: 600; color: var(--text-dim);
}
.ph-link.danger { color: var(--danger); }
.ph-link.danger.armed {
  padding: 0 12px; border-radius: 14px; color: var(--on-accent); background: var(--danger);
}
.ph-note { margin: 0; font-size: 13px; color: var(--text-dim); text-align: center; }

.ph-cube3d { width: 100%; height: min(300px, 42vh); }
.ph-cube3d twisty-player { width: 100%; height: 100%; }
.ph-cube-tools { display: flex; justify-content: center; gap: 8px; }
.ph-cube-tools .ph-seg-btn { padding: 0 16px; background: var(--surface); }
.ph-cube-tools .ph-seg-btn.on { background: var(--accent-tint); color: var(--accent-text); }

/* ---------------- smaller phones ----------------
   A 360px-wide phone has 30px less across than the mockups, and one 740px tall
   about 100px less down. Every piece keeps its place; the type and the
   padding give the room back. */
@media (max-width: 374px) {
  body.ph #topbar, body.ph .topbar-right { gap: 6px; }
  .ph-ctx { gap: 6px; padding: 0 10px; }
  body.ph #btn-daily { padding: 0 12px 0 10px; gap: 6px; }
  body.ph #scramble-text { font-size: calc(14.5px * var(--scramble-scale)); }
  body.ph #last-actions .ph-pill, body.ph #last-actions .ghost-btn.ph-pill { padding: 0 11px; font-size: 12.5px; }
  body.ph #last-actions .ph-pill svg { display: none; }
}
@media (max-height: 780px) {
  body.ph #timer-avgs { margin-top: 8px; }
  body.ph #last-actions { margin-top: 12px; }
  body.ph #timer-hint { margin-top: 10px; }
}
/* An iPhone 8 or SE in a Safari tab has about 550px: once there are averages
   to show, the hint makes room for them (a few solves in, the screen being
   the button is known), and the digits and the net give up a little more. */
@media (max-height: 620px) {
  body.ph #timer-core:has(#timer-avgs:not([hidden], .no-avg)) #timer-hint { display: none; }
  body.ph #timer-display { font-size: min(calc(var(--timer-size) * 1.45), calc((100vw - 2 * var(--phone-gutter)) / (var(--ph-chars, 5) * .58)), 11vh); }
  .ph-net-host { width: 52px; height: 39px; }
}

@media (prefers-reduced-motion: reduce) {
  .ph-dock, body.ph :is(#topbar, #scramble-zone, .ph-recent) { transition: none !important; }
  .ph-swipe, .ph-sw-dir { transition: none !important; }
}
[data-motion="off"] :is(.ph-swipe, .ph-sw-dir) { transition: none !important; }
