/* Feedscape's screens, built from the vocabulary in tokens.css (loaded first): Alda Apps' design, "Canopy".

   The page stands on a plain near-white or near-black ground, and the photo on the desktop apps' canvas grey. Glass is
   only for what floats over something that moves: the top bar over the page scrolling under it, the view capsule over
   the stage, the phone's action bar and the toast. What sits on glass, or on a card, is a plain fill; what is read or
   stayed on (the details panel, the text pages, the sheet, a notice) is an opaque plate. Things you press are capsules;
   photos are square. Nothing moves, lifts or grows on hover: only colours and fills change.

   Motion is for changes: a new picture cross-fades with the last, a panel glides to its new height (motion.js), what
   appears fades in, rising a little when it is new, and dialogs fade out as they close. */

/* Sora, the brand's face (SIL OFL 1.1, fonts/Sora-OFL.txt), for every word on the pages, as on alda-apps.com (the
   owner, 12 November 2026; until then the wordmark and the page headings only, the rest in the system's font). */
@font-face {
  font-family: 'Sora';
  src: url('fonts/Sora.woff2') format('woff2'); /* weights 400–600, Latin, tabular figures: tools/font.py */
  font-weight: 400 600;
  font-display: swap;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

/* Phones' browsers draw their own highlight over what is tapped, a rectangle in their blue that ignores rounded
   corners; the controls' own pressed fills show instead. */
html { background: var(--alda-surface); -webkit-tap-highlight-color: transparent; }

/* A column, so the main area takes the height the top bar and the footer leave. */
body {
  display: flex;
  flex-direction: column;
  margin: 0;
  min-height: 100vh;
  background: var(--alda-surface);
  color: var(--alda-ink);
  font-family: var(--alda-font-brand); /* Sora, then the system's font while it loads or where a character is missing */
  font-size: var(--alda-text-md);
  line-height: var(--alda-leading);
  -webkit-font-smoothing: antialiased;
}

/* The height of the floating top bar, which the sticky details panel and the stage measure from. */
:root { --topbar-h: calc(var(--alda-inset) + 3.25rem); }

/* The page's width, as on alda-apps.com: the content keeps `--page-gutter` from the window's edges, and the floating
   top bar reaches `--bar-reach` past it on each side, its mark in line with the content's edge. The mark keeps its
   place in the bar at every width: on a phone, where the gutter is narrower than the reach, the bar keeps 0.5rem from
   the window and the mark sits a little inside the content's edge, rather than jumping out to it. */
:root {
  --content-max: 88rem;
  --page-gutter: clamp(1.75rem, 2vw, 2.5rem); /* at least the bar's reach and 0.5rem of window round it */
  --bar-reach: 1.25rem;
}
/* A scrollbar that comes and goes (one page scrolls, the other doesn't) would shift the bar and the content. */
html { scrollbar-gutter: stable; }

main { flex: 1 0 auto; display: flex; flex-direction: column; }

/* ----------------------------------------------------------------------------------------------------------- glass */

/* The family's glass: the blurred, slightly more colourful backdrop, the tint, the sheen from the top, an edge lit from
   above (::before) and a fine grain (::after), both under the content. Each pane sets its own position and shape. The
   tint is thin, and thicker only over the columns where a photo is under the pane (glass.js sets `--alda-glass-cells`).
   Weak text on it leans towards the text colour, which keeps it at 4.5:1 over a white or a black photo. */
.glass {
  --alda-ink-dim: color-mix(in srgb, var(--alda-grey-11) 60%, var(--alda-grey-12));
  isolation: isolate;
  background-image:
    var(--alda-sheen),
    var(--alda-glass-cells, linear-gradient(var(--alda-glass-tint), var(--alda-glass-tint)));
  box-shadow: var(--alda-elevation-2);
  -webkit-backdrop-filter: var(--alda-glass-filter);
  backdrop-filter: var(--alda-glass-filter);
}
.glass::before,
.glass::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
}
.glass::before {
  padding: 1px;
  background: linear-gradient(180deg, var(--alda-edge-up), var(--alda-edge-side) 50%, var(--alda-edge-down)) border-box;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
.glass::after {
  background-image: var(--alda-grain-image);
  background-size: 128px;
  opacity: var(--alda-grain);
}

/* Blur is what glass costs a phone's GPU most, redone every frame. Devices short of memory (main.js marks them `lite`)
   tend to have a slow GPU as well: there nothing blurs, and the glass is all but opaque instead. */
:root.lite {
  --alda-glass-filter: none;
  --alda-scrim-filter: none;
  --alda-glass-tint: light-dark(rgb(244 244 244 / 95%), rgb(31 31 31 / 95%));
  --alda-glass-dense: var(--alda-glass-tint);
}

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

button, input { font: inherit; color: inherit; }

/* Every button is a capsule. The ordinary kind is a plain fill of the control grey; hover and press darken it a
   step. */
button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--alda-space-2);
  min-height: var(--alda-control);
  padding: 0 var(--alda-space-4);
  border: 0;
  border-radius: var(--alda-radius-pill);
  background-color: var(--alda-track);
  color: var(--alda-ink);
  font-size: var(--alda-text-sm);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--alda-motion-fast) var(--alda-ease),
    border-color var(--alda-motion-fast) var(--alda-ease),
    color var(--alda-motion-fast) var(--alda-ease);
}
button:hover:not(:disabled) { background-color: color-mix(in srgb, var(--alda-ink) 13%, transparent); }
button:active:not(:disabled) { background-color: color-mix(in srgb, var(--alda-ink) 18%, transparent); }
button:disabled { box-shadow: none; opacity: 0.5; cursor: default; }

/* The one thing on the screen that finishes the job: filled with Feedscape blue, the logo's, rather than the text
   colour the other Alda Apps apps use (the owner's choice, 10 November 2026). Hover and press take it a step towards
   the text colour: darker in the light theme, paler in the dark. */
button.primary {
  background-color: var(--alda-accent);
  box-shadow: var(--alda-elevation-1);
  color: var(--alda-accent-ink);
}
button.primary:hover:not(:disabled) { background-color: color-mix(in srgb, var(--alda-accent) 86%, var(--alda-ink)); }
button.primary:active:not(:disabled) { background-color: color-mix(in srgb, var(--alda-accent) 76%, var(--alda-ink)); }

/* A text button: no fill until the pointer is on it. */
button.quiet {
  min-height: var(--alda-control-sm);
  padding: 0 var(--alda-space-3);
  background-color: transparent;
  color: var(--alda-ink-dim);
}
button.quiet:hover:not(:disabled) { background-color: var(--alda-fill-hover); color: var(--alda-ink); }
button.quiet:active:not(:disabled) { background-color: var(--alda-fill-press); }

/* Focus is a ring and a soft halo, in the accent, on everything that takes it. */
:focus-visible { outline: var(--alda-focus-width) solid var(--alda-accent); outline-offset: var(--alda-focus-offset); }
button:focus-visible { box-shadow: var(--alda-focus-halo); }
button.primary:focus-visible { box-shadow: var(--alda-elevation-1), var(--alda-focus-halo); }

.spinner {
  display: inline-block;
  width: 1rem;
  height: 1rem;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  vertical-align: -3px;
}
@keyframes spin { to { transform: rotate(360deg); } }
/* Nothing turns for ever with reduced motion: the words beside the spinner say what is going on. */
@media (prefers-reduced-motion: reduce) { .spinner { display: none; } }

/* --------------------------------------------------------------------------------------------------------- top bar */

/* One capsule of glass floating over the top of the page, which scrolls under it: the app's mark and name, what is
   open, then New photo. */
.topbar {
  position: sticky;
  top: 0;
  z-index: var(--alda-z-bar);
  padding: var(--alda-inset) max(0.5rem, calc(var(--page-gutter) - var(--bar-reach))) 0;
  pointer-events: none;
}
.topbar-bar {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--alda-space-3);
  max-width: calc(var(--content-max) + 2 * var(--bar-reach));
  min-height: 3.25rem;
  margin: 0 auto;
  padding: var(--alda-space-2) var(--alda-space-2) var(--alda-space-2) var(--bar-reach);
  border-radius: var(--alda-radius-pill);
  pointer-events: auto;
}

.brand {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: var(--alda-space-3);
  border-radius: var(--alda-radius-sm);
  color: inherit;
  text-decoration: none;
}
/* The app icon (favicon.svg), small, as alda-apps.com shows each app's. */
.brand-mark { display: block; flex: none; width: 1.75rem; height: 1.75rem; }
/* The name as alda-apps.com sets its own in its header: Sora Medium, 16 px, a little tightened. */
.brand-name {
  font-family: var(--alda-font-brand);
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: -0.015em;
}
.photo-info {
  min-width: 0;
  padding-left: var(--alda-space-3);
  border-left: 1px solid var(--alda-divider);
  overflow: hidden;
  color: var(--alda-ink-dim);
  font-size: var(--alda-text-sm);
  font-variant-numeric: tabular-nums;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.photo-info:empty { display: none; }
#new-photo { margin-left: auto; }
#new-photo:not([hidden]), .photo-info:not(:empty) { animation: fade-in var(--alda-motion-enter) var(--alda-ease); }

/* Light, System or Dark (theme.js): three round buttons in a track, the picked one standing up out of it, the thumb
   sliding to it. Hidden without scripts, when the page follows the system. */
.theme-switch {
  position: relative;
  display: flex;
  flex: none;
  padding: 3px;
  border-radius: var(--alda-radius-pill);
  background: var(--alda-track);
}
.topbar-bar > .theme-switch { margin-left: auto; }
#new-photo:not([hidden]) ~ .theme-switch { margin-left: 0; }
:root:not(.js) .theme-switch { display: none; }
.theme-switch button {
  position: relative;
  z-index: 1;
  width: 1.875rem;
  min-height: 1.875rem;
  padding: 0;
  background: none;
  color: var(--alda-ink-dim);
}
.theme-switch button:hover:not(:disabled),
.theme-switch button:active:not(:disabled) { background: none; color: var(--alda-ink); }
.theme-switch button[aria-pressed="true"] { color: var(--alda-ink); }
.theme-switch svg {
  width: 1rem;
  height: 1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.theme-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 1.875rem;
  height: 1.875rem;
  border-radius: 50%;
  background: var(--alda-raised);
  box-shadow: var(--alda-elevation-1), inset 0 0 0 1px var(--alda-rail);
  transition: translate var(--alda-motion) var(--alda-ease);
}
:root[data-pref="system"] .theme-thumb { translate: 1.875rem 0; }
:root[data-pref="dark"] .theme-thumb { translate: 3.75rem 0; }
@media (prefers-reduced-motion: reduce) { .theme-thumb { transition: none; } }

/* A change of theme fades in, as on alda-apps.com: for 0.3 s after one (theme.js marks the page with `theme-fade`) every
   colour eases to its new value, the thumb still sliding at its own pace. The change itself is made at once; this is
   only how it looks. Glass takes the new theme at once: its tint and edge are gradients, which can't ease. */
:root.theme-fade,
:root.theme-fade *,
:root.theme-fade *::before,
:root.theme-fade *::after {
  transition:
    background-color 300ms ease, color 300ms ease, border-color 300ms ease, outline-color 300ms ease,
    fill 300ms ease, stroke 300ms ease, box-shadow 300ms ease,
    translate var(--alda-motion) var(--alda-ease);
}
/* What stands on glass changes at once with it: words easing on a pane that has already changed would sink into it
   for a moment and come back, a blink. A pane's words take their colour from the page, which is easing, so meanwhile
   the pane states the text colour itself. */
:root.theme-fade .glass,
:root.theme-fade .glass *,
:root.theme-fade .glass *::before,
:root.theme-fade .glass *::after {
  transition: translate var(--alda-motion) var(--alda-ease);
}
:root.theme-fade .glass { color: var(--alda-ink); }
@media (prefers-reduced-motion: reduce) {
  :root.theme-fade, :root.theme-fade *, :root.theme-fade *::before, :root.theme-fade *::after { transition: none; }
}

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

.picker {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 1;
  gap: var(--alda-space-5);
  padding: var(--alda-space-6) var(--alda-space-4) var(--alda-space-7);
  text-align: center;
}
.hero h1 {
  margin: 0 0 var(--alda-space-3);
  font-family: var(--alda-font-brand);
  font-size: var(--alda-display-md);
  font-weight: 500;
  letter-spacing: var(--alda-tracking-display);
  line-height: var(--alda-leading-display);
  text-wrap: balance;
}
.hero p {
  margin: 0 auto;
  max-width: 34rem;
  color: var(--alda-ink-dim);
  font-size: var(--alda-text-lg);
  text-wrap: pretty;
}
/* On a phone the lead is a size down, so in Sora it keeps to four lines and the footer to the first screen. */
@media (max-width: 30rem) { .hero p { font-size: var(--alda-text-md); } }

/* The way in: the dashed outline of a photo not there yet, on a plain plate; the dash turns to the accent while the
   pointer or a dragged file is over it. */
.drop {
  flex-direction: column;
  gap: var(--alda-space-1);
  width: min(35rem, 100%);
  min-height: 14.5rem;
  padding: var(--alda-space-6);
  border: 2px dashed color-mix(in srgb, var(--alda-ink-dim) 55%, transparent);
  border-radius: var(--alda-radius-lg);
  background-color: var(--alda-card);
  white-space: normal;
}
.drop:hover:not(:disabled), body.dragging .drop {
  border-color: var(--alda-accent);
  background-color: color-mix(in srgb, var(--alda-accent) 4%, var(--alda-card));
}
.drop:active:not(:disabled) { background-color: color-mix(in srgb, var(--alda-accent) 8%, var(--alda-card)); }
.drop-icon {
  width: 3.5rem;
  height: 3.5rem;
  margin-bottom: var(--alda-space-4);
  padding: 1rem;
  border-radius: 50%;
  background: var(--alda-accent-soft);
  color: var(--alda-accent);
}
/* "Choose a photo" looks as the primary button does: on this screen it is the one thing that starts the job. The
   whole plate is the button, so the capsule is drawn, not a button of its own. */
.drop-title {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  margin-bottom: var(--alda-space-2);
  padding: 0 var(--alda-space-5);
  border-radius: var(--alda-radius-pill);
  background-color: var(--alda-accent);
  box-shadow: var(--alda-elevation-1);
  color: var(--alda-accent-ink);
  font-size: var(--alda-text-md);
  font-weight: 600;
  transition: background-color var(--alda-motion-fast) var(--alda-ease);
}
.drop:hover:not(:disabled) .drop-title { background-color: color-mix(in srgb, var(--alda-accent) 86%, var(--alda-ink)); }
.drop:active:not(:disabled) .drop-title { background-color: color-mix(in srgb, var(--alda-accent) 76%, var(--alda-ink)); }
.drop-sub { color: var(--alda-ink-dim); font-size: var(--alda-text-sm); font-weight: 400; }

/* What you get: each shape drawn in its own proportions, as the option cards will show them, its name under it. */
.shapes {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--alda-space-3) var(--alda-space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}
.shapes li {
  display: grid;
  justify-items: center;
  gap: var(--alda-space-1);
  min-width: 3rem;
  color: var(--alda-ink-dim);
  font-size: var(--alda-text-xs);
}
.shapes svg { height: 2rem; width: auto; }
/* On a phone the seven stay on one row, closer together, so the footer keeps its place on the first screen. */
@media (max-width: 30rem) {
  .shapes { flex-wrap: nowrap; gap: var(--alda-space-2); }
  .shapes li { min-width: 0; }
  .shapes svg { height: 1.75rem; }
}
/* The narrowest phones have no room for seven names in a row: two rows there. */
@media (max-width: 22rem) { .shapes { flex-wrap: wrap; max-width: 15rem; gap: var(--alda-space-2) var(--alda-space-3); } }
.shapes rect { fill: var(--alda-card); stroke: currentColor; stroke-width: 1.4; }
.shapes .photo { fill: var(--alda-track); stroke: none; }
.shapes .cut { fill: none; stroke: currentColor; stroke-width: 1.2; stroke-dasharray: 2 2; }
.status { min-height: 1.5em; margin: 0; color: var(--alda-ink-dim); font-size: var(--alda-text-sm); }
.status:empty { display: none; }
.status.error { color: var(--alda-bad); }
body.busy .drop { opacity: 0.6; pointer-events: none; }
.fineprint {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--alda-space-2);
  margin: 0;
  color: var(--alda-ink-dim);
  font-size: var(--alda-text-xs);
}
.fineprint svg {
  flex: none;
  width: 0.9375rem; height: 0.9375rem;
  fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}

/* Dropping a file anywhere: the window frosts over and says what will happen. */
.drop-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--alda-z-overlay);
  display: none;
  place-items: center;
  background: color-mix(in srgb, var(--alda-surface) 60%, transparent);
  -webkit-backdrop-filter: var(--alda-scrim-filter);
  backdrop-filter: var(--alda-scrim-filter);
  pointer-events: none;
}
.drop-overlay::before {
  content: '';
  position: absolute;
  inset: var(--alda-space-4);
  border: 2px dashed var(--alda-accent);
  border-radius: var(--alda-radius-lg);
}
.drop-overlay span {
  padding: var(--alda-space-3) var(--alda-space-5);
  border: 1px solid var(--alda-border);
  border-radius: var(--alda-radius-pill);
  background: var(--alda-card);
  box-shadow: var(--alda-elevation-3);
  font-size: var(--alda-text-xl);
  font-weight: 600;
}
body.dragging .drop-overlay { display: grid; animation: fade-in var(--alda-motion) var(--alda-ease); }

/* ------------------------------------------------------------------------------------------------------- workspace */

.workspace {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 21.5rem;
  grid-template-areas: "stage details" "options details";
  grid-template-rows: auto 1fr;
  align-items: start;
  gap: var(--alda-space-4);
  width: 100%;
  max-width: calc(var(--content-max) + 2 * var(--page-gutter));
  margin: 0 auto;
  padding: var(--alda-space-4) var(--page-gutter);
}
/* The first photo: the stage and the panel rise in, the panel a moment later; the cards follow one by one (cards.js). */
.workspace > .stage-area, .workspace > .details {
  animation: rise-in var(--alda-motion-enter) var(--alda-ease) backwards;
}
.workspace > .details { animation-delay: 60ms; }

/* The work: a card like the details panel beside it, the photo centred in it, square-cornered, never tinted or blurred,
   and the view capsule centred below it, in the card's own space, so the photo is never under the glass. A panorama's
   white first slide shows where it ends by its hairline (.stage-edges). */
.stage-area {
  grid-area: stage;
  position: relative;
  display: flex;
  flex-direction: column;
  height: clamp(340px, calc(100vh - var(--topbar-h) - 250px), 820px);
  padding: var(--alda-space-5);
  border: 1px solid var(--alda-border);
  border-radius: var(--alda-radius-lg);
  background: var(--alda-card);
  overflow: hidden;
}
/* The stage's pictures fade into each other in a group of their own, the outgoing one added to the incoming (plus-lighter),
   so where they overlap the light stays even, rather than dipping to the card's colour halfway. */
.stage-box { position: relative; flex: 1; min-height: 0; display: grid; place-items: center; isolation: isolate; }
.stage-frame { position: relative; line-height: 0; }
.stage-ghost {
  position: absolute;
  opacity: 0; /* seen only while it fades out (motion.js) */
  box-shadow: 0 0 0 1px var(--alda-border);
  mix-blend-mode: plus-lighter;
  pointer-events: none;
}
#stage { display: block; cursor: grab; touch-action: none; }
#stage:active { cursor: grabbing; }
#stage.fixed { cursor: default; }

/* A panorama's slide numbers: solid labels at the foot of each slide, so the photo never shows through them. */
/* A hairline round each picture on the stage (a panorama's cover, and its parts), as round the cards' previews, so a
   photo on a white or black border shows where it ends. Outside the picture, never over it. */
.stage-edges { position: absolute; inset: 0; pointer-events: none; }
.stage-edges span { position: absolute; top: 0; bottom: 0; box-shadow: 0 0 0 1px var(--alda-border); }

.slide-marks { position: absolute; inset: 0; pointer-events: none; }
.slide-marks span {
  position: absolute;
  bottom: var(--alda-space-2);
  display: grid;
  place-items: center;
  min-width: 1.375rem;
  height: 1.375rem;
  margin-left: var(--alda-space-2);
  padding: 0 0.3125rem;
  border-radius: var(--alda-radius-pill);
  background: rgb(0 0 0 / 60%);
  color: #ffffff;
  font-size: var(--alda-text-xs);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

/* The view capsule: Result or Whole photo, the zoom, Reset. View controls only, centred below the photo. */
.stage-tools {
  position: relative;
  z-index: 1;
  align-self: center;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--alda-space-1) var(--alda-space-2);
  max-width: 100%;
  order: 1;
  margin: var(--alda-space-4) 0 0;
  padding: var(--alda-space-1);
  border-radius: 1.3125rem;
}
.stage-tools .hint {
  margin: 0;
  padding: var(--alda-space-1) var(--alda-space-3);
  color: var(--alda-ink-dim);
  font-size: var(--alda-text-xs);
}
.stage-tools .seg { background: var(--alda-track); }

/* The slider: its label, then a 4 px rail filled with the accent up to a solid knob (adjust.js sets `--fill`). */
.zoom {
  display: flex;
  align-items: center;
  gap: var(--alda-space-2);
  padding: 0 var(--alda-space-2);
  color: var(--alda-ink-dim);
  font-size: var(--alda-text-sm);
}
/* The divider between groups in a capsule. */
.zoom::before {
  content: '';
  flex: none;
  width: 1px;
  height: 1rem;
  margin-right: var(--alda-space-1);
  background: color-mix(in srgb, var(--alda-ink-dim) 35%, transparent);
}
.zoom input {
  --fill: 0%;
  -webkit-appearance: none;
  appearance: none;
  width: 8.75rem;
  height: 1.375rem;
  margin: 0;
  background: none;
  cursor: pointer;
}
.zoom input::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: var(--alda-radius-pill);
  background: linear-gradient(90deg, var(--alda-accent) var(--fill), var(--alda-rail) var(--fill));
}
.zoom input::-moz-range-track { height: 4px; border-radius: var(--alda-radius-pill); background: var(--alda-rail); }
.zoom input::-moz-range-progress { height: 4px; border-radius: var(--alda-radius-pill); background: var(--alda-accent); }
.zoom input::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 17px;
  height: 17px;
  margin-top: -6.5px;
  border-radius: 50%;
  background: light-dark(#ffffff, var(--alda-grey-12));
  box-shadow: 0 0 0 1px var(--alda-rail), var(--alda-elevation-1);
}
.zoom input::-moz-range-thumb {
  width: 17px;
  height: 17px;
  border: 0;
  border-radius: 50%;
  background: light-dark(#ffffff, var(--alda-grey-12));
  box-shadow: 0 0 0 1px var(--alda-rail), var(--alda-elevation-1);
}
.zoom input:focus-visible { outline-offset: 3px; border-radius: var(--alda-radius-pill); }

/* Shown until the first drag or zoom, then remembered: a caption on the photo, white on dark, as the family's. */
.stage-hint {
  position: absolute;
  left: 50%;
  bottom: var(--alda-inset);
  transform: translateX(-50%);
  max-width: calc(100% - 2rem);
  padding: var(--alda-space-1) var(--alda-space-3);
  border-radius: var(--alda-radius-pill);
  background: rgb(0 0 0 / 60%);
  color: #ffffff;
  font-size: var(--alda-text-xs);
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}
.stage-hint:not([hidden]) { animation: fade-in var(--alda-motion-enter) var(--alda-ease); }

/* Over the photo shown while the next one opens: fades in, unless the next opens at once, and out again. */
.busy-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  align-content: center;
  gap: var(--alda-space-3);
  background: color-mix(in srgb, var(--alda-card) 88%, transparent);
  color: var(--alda-ink);
  font-size: var(--alda-text-sm);
  font-weight: 600;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--alda-motion-slow) var(--alda-ease), visibility 0s var(--alda-motion-slow);
}
body.busy .busy-overlay {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--alda-motion-slow) var(--alda-ease) 120ms, visibility 0s;
}
/* Hidden, its spinner stops, rather than turning unseen for ever. */
body:not(.busy) .busy-overlay .spinner { animation: none; }

/* Segmented controls: a track of the control grey; the picked choice stands up out of it, with a thin outline, so it is
   not marked by colour alone. */
.seg {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 3px;
  border-radius: 1.0625rem;
  background: var(--alda-track);
}
.seg button {
  min-height: 1.75rem;
  padding: 0 var(--alda-space-3);
  background: none;
  color: var(--alda-ink-dim);
  font-size: var(--alda-text-sm);
  transition:
    background-color var(--alda-motion) var(--alda-ease),
    box-shadow var(--alda-motion) var(--alda-ease),
    color var(--alda-motion) var(--alda-ease);
}
.seg button:hover:not(:disabled) { background: none; color: var(--alda-ink); }
.seg button[aria-pressed="true"],
.seg button[aria-pressed="true"]:hover:not(:disabled) {
  background: var(--alda-raised);
  box-shadow: var(--alda-elevation-1), inset 0 0 0 1px var(--alda-rail);
  color: var(--alda-ink);
}
.seg button:focus-visible { box-shadow: var(--alda-focus-halo); }
.seg button[aria-pressed="true"]:focus-visible {
  box-shadow: var(--alda-elevation-1), inset 0 0 0 1px var(--alda-rail), var(--alda-focus-halo);
}

/* --------------------------------------------------------------------------------------------------------- details */

/* A plate beside the stage: nothing moves under it, so it is a card, not glass. */
.details {
  grid-area: details;
  position: sticky;
  top: calc(var(--topbar-h) + var(--alda-space-4));
  display: flex;
  flex-direction: column;
  gap: var(--alda-space-3);
  padding: var(--alda-space-5);
  border: 1px solid var(--alda-border);
  border-radius: var(--alda-radius-lg);
  background: var(--alda-card);
}
.details p { margin: 0; }
.details-head { display: flex; align-items: center; gap: var(--alda-space-2) var(--alda-space-3); flex-wrap: wrap; }
.details h2 {
  margin: 0;
  font-size: var(--alda-text-xl);
  font-weight: 600;
  letter-spacing: var(--alda-tracking-title);
  line-height: var(--alda-leading-tight);
}
.reason { color: var(--alda-accent); font-size: var(--alda-text-sm); font-weight: 600; text-wrap: pretty; }
.dims { font-size: var(--alda-text-lg); font-variant-numeric: tabular-nums; font-weight: 600; }
.kept { color: var(--alda-ink-dim); font-size: var(--alda-text-sm); }
.actions { display: flex; flex-wrap: wrap; gap: var(--alda-space-2); }
.actions button { min-height: var(--alda-control-lg); padding: 0 var(--alda-space-5); font-size: var(--alda-text-md); }
.actions .primary { flex: 1 1 auto; }

/* A note: marked by a rule down its edge as well as by colour. */
.warnings {
  margin: 0;
  padding: var(--alda-space-3) var(--alda-space-3) var(--alda-space-3) var(--alda-space-6);
  border-left: 3px solid var(--alda-warn);
  border-radius: var(--alda-radius-md);
  background-color: color-mix(in srgb, var(--alda-warn) 10%, var(--alda-card));
  font-size: var(--alda-text-sm);
  line-height: 1.45;
}
.warnings:empty { display: none; }

.section {
  display: flex;
  flex-direction: column;
  gap: var(--alda-space-2);
  padding-top: var(--alda-space-3);
  border-top: 1px solid var(--alda-divider);
}
.choice-row { display: flex; align-items: center; gap: var(--alda-space-2); flex-wrap: wrap; font-size: var(--alda-text-sm); }
.choice-row > span { min-width: 5.5rem; color: var(--alda-ink-dim); font-size: var(--alda-text-xs); }
.choice-row small { color: var(--alda-ink-dim); font-size: var(--alda-text-xs); }

/* An on/off setting: its label with what it does under it, and the switch at the right. The whole row toggles. */
.switch-row {
  display: flex;
  align-items: center;
  gap: var(--alda-space-4);
  padding: var(--alda-space-1) 0;
  cursor: pointer;
}
.switch-text { display: flex; flex: 1; flex-direction: column; gap: 2px; min-width: 0; }
.switch-label { font-size: var(--alda-text-sm); font-weight: 500; }
.switch-hint { color: var(--alda-ink-dim); font-size: var(--alda-text-xs); line-height: 1.4; text-wrap: pretty; }
.switch-row input {
  -webkit-appearance: none;
  appearance: none;
  position: relative;
  flex: none;
  width: 2.5rem;
  height: 1.5rem;
  margin: 0;
  border-radius: var(--alda-radius-pill);
  background-color: var(--alda-track-strong);
  cursor: pointer;
  transition: background-color var(--alda-motion) var(--alda-ease);
}
.switch-row input::before {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  background-color: #ffffff;
  box-shadow: var(--alda-elevation-1);
  transition: transform var(--alda-motion) var(--alda-ease), background-color var(--alda-motion) var(--alda-ease);
}
.switch-row:hover input:not(:checked) { background-color: color-mix(in srgb, var(--alda-ink) 30%, transparent); }
.switch-row input:checked { background-color: var(--alda-accent); }
.switch-row input:checked::before { transform: translateX(1rem); background-color: var(--alda-accent-ink); }
.switch-row input:focus-visible { box-shadow: var(--alda-focus-halo); }

/* What the profile grid will show: square-cornered, as photos are. */
.grid-preview { display: flex; gap: var(--alda-space-3); align-items: center; }
.grid-preview canvas { flex: none; width: 60px; height: 80px; box-shadow: 0 0 0 1px var(--alda-border); }
.grid-preview strong { font-size: var(--alda-text-sm); font-weight: 600; }
.grid-preview p { color: var(--alda-ink-dim); font-size: var(--alda-text-xs); }

.tip {
  padding: var(--alda-space-3);
  border-radius: var(--alda-radius-md);
  background: var(--alda-track);
  color: var(--alda-ink-dim);
  font-size: var(--alda-text-xs);
  text-wrap: pretty;
}

/* Export size: a row at the foot of the panel saying the width chosen, with a chevron; it opens on the three widths,
   each with a word on what it is for, across the panel. The row's fill reaches a little past the text, which lines up
   with the rest of the panel. */
.size { padding-top: var(--alda-space-2); border-top: 1px solid var(--alda-divider); }
.size-toggle {
  justify-content: flex-start;
  width: calc(100% + 2 * var(--alda-space-3));
  margin: 0 calc(-1 * var(--alda-space-3));
  padding: 0 var(--alda-space-3);
  border-radius: var(--alda-radius-md);
  background-color: transparent;
  font-weight: 500;
}
.size-toggle:hover:not(:disabled) { background-color: var(--alda-fill-hover); }
.size-toggle:active:not(:disabled) { background-color: var(--alda-fill-press); }
.size-value { margin-left: auto; color: var(--alda-ink-dim); font-weight: 400; font-variant-numeric: tabular-nums; }
/* A chevron drawn by two borders: down while closed, up while open. */
.size-toggle::after {
  content: '';
  flex: none;
  width: 0.4375rem;
  height: 0.4375rem;
  margin: 0 0.125rem 0 var(--alda-space-1);
  border: solid var(--alda-ink-dim);
  border-width: 0 1.5px 1.5px 0;
  translate: 0 -0.125rem;
  rotate: 45deg;
  transition: rotate var(--alda-motion-slow) var(--alda-ease), translate var(--alda-motion-slow) var(--alda-ease);
}
.size-toggle[aria-expanded="true"]::after { translate: 0 0.125rem; rotate: 225deg; }
.size-choices { padding: var(--alda-space-1) 0 var(--alda-space-1); }
.size-seg { display: grid; grid-template-columns: repeat(3, 1fr); border-radius: var(--alda-radius-md); }
.size-seg button {
  flex-direction: column;
  gap: 0;
  min-height: 2.875rem;
  padding: var(--alda-space-1) var(--alda-space-2);
  border-radius: calc(var(--alda-radius-md) - 3px);
  line-height: 1.25;
}
.size-px { font-variant-numeric: tabular-nums; }
.size-note { color: var(--alda-ink-dim); font-size: var(--alda-text-2xs); font-weight: 500; }

/* "Suggested": a word with a dot, in the accent's tint. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.0625rem var(--alda-space-2);
  border-radius: var(--alda-radius-pill);
  background-color: var(--alda-accent-soft);
  color: var(--alda-accent);
  font-size: var(--alda-text-xs);
  font-weight: 600;
  line-height: 1.5;
}
.badge::before { content: ''; width: 0.4rem; height: 0.4rem; border-radius: 50%; background: currentColor; }

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

.options { grid-area: options; display: flex; flex-wrap: wrap; gap: var(--alda-space-3) var(--alda-space-4); min-width: 0; }
.option-group { min-width: 0; max-width: 100%; }
/* Section labels: small spaced capitals, weak. */
.option-group h3 {
  margin: 0 0 var(--alda-space-2);
  padding-left: var(--alda-space-1);
  color: var(--alda-ink-dim);
  font-size: var(--alda-text-2xs);
  font-weight: 600;
  letter-spacing: var(--alda-tracking-caps);
  text-transform: uppercase;
}
.option-row { display: flex; flex-wrap: wrap; gap: var(--alda-space-2); padding: 2px; }
/* A tile for each option: a plain card; picked, the accent's tint with an outline in the accent, and the label in the
   accent, so it is not marked by colour alone. */
.option {
  position: relative;
  flex: none;
  flex-direction: column;
  gap: 1px;
  min-width: 5.5rem;
  padding: var(--alda-space-2) var(--alda-space-2) 0.45rem;
  border: 1px solid var(--alda-border);
  border-radius: var(--alda-radius-md);
  background-color: var(--alda-card);
  font-weight: 400;
  white-space: normal;
}
.option {
  transition:
    background-color var(--alda-motion) var(--alda-ease),
    border-color var(--alda-motion) var(--alda-ease),
    box-shadow var(--alda-motion) var(--alda-ease);
}
.option:hover:not(:disabled) { background-color: color-mix(in srgb, var(--alda-ink) 4%, var(--alda-card)); }
.option:active:not(:disabled) { background-color: color-mix(in srgb, var(--alda-ink) 8%, var(--alda-card)); }
.option[aria-pressed="true"],
.option[aria-pressed="true"]:hover:not(:disabled) {
  border-color: var(--alda-accent);
  background-color: color-mix(in srgb, var(--alda-accent) 9%, var(--alda-card));
  box-shadow: inset 0 0 0 1px var(--alda-accent);
}
.option[aria-pressed="true"] .option-label { color: var(--alda-accent); }
.option[aria-pressed="true"]:focus-visible { box-shadow: inset 0 0 0 1px var(--alda-accent), var(--alda-focus-halo); }
.thumb-area { display: flex; align-items: center; justify-content: center; height: 96px; margin-bottom: 5px; }
.thumb { position: relative; display: block; line-height: 0; }
.option canvas { display: block; background: var(--alda-track); box-shadow: 0 0 0 1px var(--alda-border); }
.option-label {
  font-size: var(--alda-text-sm);
  font-weight: 600;
  line-height: var(--alda-leading);
  transition: color var(--alda-motion) var(--alda-ease);
}
.option-meta { color: var(--alda-ink-dim); font-size: var(--alda-text-xs); font-variant-numeric: tabular-nums; line-height: 1.4; }
.option-meta.full { color: var(--alda-accent); font-weight: 600; }
/* The badge sits inside the preview, so it never sticks out of the card; solid, because it is on a photo. */
.thumb .badge {
  position: absolute;
  top: 4px;
  left: 4px;
  padding: 0 0.375rem;
  background-color: var(--alda-accent);
  color: var(--alda-accent-ink);
  font-size: 0.65625rem;
  line-height: 1.125rem;
  white-space: nowrap;
}
.thumb .badge::before { display: none; }

/* ------------------------------------------------------------------------------------------------ footer and pages */

/* The links to the pages about Feedscape, and the small print, under everything. */
.site-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0 var(--alda-space-4);
  padding: var(--alda-space-3) var(--alda-space-4) calc(var(--alda-space-4) + env(safe-area-inset-bottom));
  color: var(--alda-ink-dim);
  font-size: var(--alda-text-xs);
  text-align: center;
}
.site-footer nav { display: flex; gap: var(--alda-space-4); }
.site-footer p { margin: 0; }
.site-footer a {
  display: inline-block;
  padding: var(--alda-space-1) 0;
  border-radius: var(--alda-radius-xs);
  color: inherit;
  text-decoration: none;
  transition: color var(--alda-motion-fast) var(--alda-ease);
}
.site-footer a:hover { color: var(--alda-ink); text-decoration: underline; }
.site-footer a[aria-current="page"] { color: var(--alda-ink); font-weight: 600; }

/* The pages about Feedscape. Privacy and Terms: one plate of text, a comfortable measure wide. How it works, What's
   new and Contact (`.doc.sections`): their title and lead on the page's ground, then each part in a card of its own. */
.page { padding: var(--alda-space-5) var(--alda-space-4) var(--alda-space-7); }
.doc {
  width: 100%;
  max-width: 44rem;
  margin: 0 auto;
  padding: var(--alda-space-6);
  border: 1px solid var(--alda-border);
  border-radius: var(--alda-radius-lg);
  background: var(--alda-card);
  text-wrap: pretty;
}
.doc h1, .doc h2 { font-family: var(--alda-font-brand); }
.doc h1 {
  margin: 0 0 var(--alda-space-1);
  font-size: var(--alda-display-sm);
  font-weight: 600;
  letter-spacing: var(--alda-tracking-display);
  line-height: var(--alda-leading-tight);
}
.doc h2 {
  margin: var(--alda-space-6) 0 var(--alda-space-2);
  font-size: var(--alda-text-lg);
  font-weight: 600;
  letter-spacing: var(--alda-tracking-title);
  line-height: var(--alda-leading-tight);
}
.doc h3 { margin: var(--alda-space-5) 0 var(--alda-space-1); font-size: var(--alda-text-md); font-weight: 600; }
.doc h2 + h3 { margin-top: 0; }
.doc p, .doc ul, .doc ol { margin: 0 0 var(--alda-space-3); }
.doc ul, .doc ol { padding-left: var(--alda-space-5); }
.doc li + li { margin-top: var(--alda-space-1); }
.doc > :first-child { margin-top: 0; }
.doc > :last-child { margin-bottom: 0; }
.doc a { border-radius: 2px; color: var(--alda-accent); text-underline-offset: 0.15em; }
.doc .updated { margin-bottom: var(--alda-space-5); color: var(--alda-ink-dim); font-size: var(--alda-text-sm); }
.doc .lead { font-size: var(--alda-text-lg); }
/* What's new: each version's number, then the day it went live, then what changed. */
.doc .version h2 { margin-bottom: var(--alda-space-1); }
.doc .released { color: var(--alda-ink-dim); font-size: var(--alda-text-sm); }
/* The Contact page's way to write to us: a link filled as the page's one primary button, the address beside it for
   those without a mail app. */
.doc .mail-us { display: flex; flex-wrap: wrap; align-items: center; gap: var(--alda-space-2) var(--alda-space-4); }
.doc .mail-us span { user-select: all; }
/* The same button takes a reader on: "Try it with a photo" under How it works, "Open Feedscape" on the 404 page. */
.doc a.mail, .doc a.go, a.go {
  display: inline-flex;
  align-items: center;
  min-height: var(--alda-control);
  padding: 0 var(--alda-space-4);
  border-radius: var(--alda-radius-pill);
  background-color: var(--alda-accent);
  box-shadow: var(--alda-elevation-1);
  color: var(--alda-accent-ink);
  font-size: var(--alda-text-sm);
  font-weight: 600;
  text-decoration: none;
  transition: background-color var(--alda-motion-fast) var(--alda-ease);
}
.doc a.mail:hover, a.go:hover { background-color: color-mix(in srgb, var(--alda-accent) 86%, var(--alda-ink)); }
.doc a.mail:active, a.go:active { background-color: color-mix(in srgb, var(--alda-accent) 76%, var(--alda-ink)); }
.page-next { margin: var(--alda-space-5) 0 0; text-align: center; }
.doc h1 + .lead { margin-top: var(--alda-space-4); }

/* A page in cards: the article itself is no plate; its header stands on the ground and each section, step and version
   is a card. In the sheet, the sheet takes the ground's colour, so the page looks as it does on its own. */
.doc.sections {
  display: flex;
  flex-direction: column;
  gap: var(--alda-space-3);
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
}
.doc.sections > * { margin: 0; }
.doc.sections > header { padding: var(--alda-space-2) 0 var(--alda-space-3); }
.doc.sections > section, .doc .steps > li {
  padding: var(--alda-space-5);
  border: 1px solid var(--alda-border);
  border-radius: var(--alda-radius-lg);
  background: var(--alda-card);
}
.doc.sections > section > :first-child { margin-top: 0; }
.doc.sections > section > :last-child { margin-bottom: 0; }
/* How it works: the three steps side by side, each numbered in a disc of the accent's tint. */
.doc .steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--alda-space-3);
  padding: 0;
  list-style: none;
  counter-reset: step;
}
.doc .steps > li {
  margin: 0;
  padding: var(--alda-space-4);
  color: var(--alda-ink-dim);
  font-size: var(--alda-text-sm);
  counter-increment: step;
}
.doc .steps > li::before {
  content: counter(step);
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  margin-bottom: var(--alda-space-3);
  border-radius: 50%;
  background: var(--alda-accent-soft);
  color: var(--alda-accent);
  font-family: var(--alda-font-brand);
  font-weight: 600;
}
.doc .steps strong {
  display: block;
  margin-bottom: var(--alda-space-1);
  color: var(--alda-ink);
  font-size: var(--alda-text-md);
  font-weight: 600;
}
/* The questions: one card, a hairline between each question and the one before. */
.doc .questions h3 { margin: var(--alda-space-4) 0 var(--alda-space-1); }
.doc .questions h3 + p { margin-bottom: 0; }
.doc .questions h3:not(h2 + h3) { padding-top: var(--alda-space-4); border-top: 1px solid var(--alda-divider); }
.doc .questions h2 + h3 { margin-top: var(--alda-space-3); }

/* ----------------------------------------------------------------------------------------------------------- sheet */

/* The footer's pages over the app (sheet.js): their article scrolling in an opaque plate in the middle of the window,
   over a dimmed, softened app. Phones get it as a sheet from the bottom. */
.sheet {
  flex-direction: column;
  width: min(44rem, calc(100% - 2 * var(--alda-space-4)));
  max-width: none;
  max-height: min(48rem, calc(100% - 2 * var(--alda-space-6)));
  padding: 0;
  border: 1px solid var(--alda-border);
  border-radius: var(--alda-radius-dialog);
  background: var(--alda-card);
  box-shadow: var(--alda-elevation-3);
  color: var(--alda-ink);
  overflow: hidden;
}
.sheet[open] { display: flex; animation: sheet-in var(--alda-motion-slow) var(--alda-ease); }
.sheet::backdrop {
  background: var(--alda-scrim);
  -webkit-backdrop-filter: var(--alda-scrim-filter);
  backdrop-filter: var(--alda-scrim-filter);
}
.sheet[open]::backdrop { animation: fade-in var(--alda-motion-slow) var(--alda-ease); }
/* Let go after a swipe down that doesn't close it (sheet.js), the sheet slides back up. */
.sheet { transition: translate var(--alda-motion-slow) var(--alda-ease); }
/* Closing, it fades and sinks a little, and the backdrop clears: where the browser can keep a closed dialog in the top
   layer for that (`overlay`); elsewhere it goes at once. */
@supports (overlay: auto) {
  .sheet, .sheet::backdrop {
    transition:
      opacity var(--alda-motion) var(--alda-ease),
      translate var(--alda-motion) var(--alda-ease),
      display var(--alda-motion) allow-discrete,
      overlay var(--alda-motion) allow-discrete;
  }
  .sheet:not([open]) { opacity: 0; translate: 0 var(--alda-rise); }
  .sheet:not([open])::backdrop { opacity: 0; }
}
.sheet-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
/* Text fades out where it scrolls under the top and bottom edges, over 3rem where there is more to scroll. The fades
   grow and shrink with the scrolling, so at either end there is none and the first and last lines are clear. Browsers
   that can't animate with scrolling get fixed fades no taller than the article's padding, which at either end cover
   only padding. The strip on the right, where the scroll bar is and no text goes, stays clear. */
@property --fade-top { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --fade-bottom { syntax: "<length>"; inherits: false; initial-value: 0px; }
.sheet-body {
  --fade-top: var(--alda-space-5);
  --fade-bottom: var(--alda-space-5);
  mask-image:
    linear-gradient(transparent, #000 var(--fade-top), #000 calc(100% - var(--fade-bottom)), transparent),
    linear-gradient(#000, #000);
  mask-size: calc(100% - var(--alda-space-4)) 100%, var(--alda-space-4) 100%;
  mask-position: left, right;
  mask-repeat: no-repeat;
}
@supports (animation-timeline: scroll()) {
  .sheet-body {
    animation: sheet-fade-top linear both, sheet-fade-bottom linear both;
    animation-timeline: scroll(self);
    animation-range: 0 var(--alda-space-7), calc(100% - var(--alda-space-7)) 100%;
  }
}
.sheet .doc { max-width: none; border: 0; border-radius: 0; background: none; }
.sheet:has(.doc.sections) { background: var(--alda-surface); }
.sheet .doc.sections { padding: var(--alda-space-5); }
/* A page followed from another in the sheet fades in. */
.sheet-body > .doc { animation: fade-in var(--alda-motion) var(--alda-ease); }
.sheet h1 { margin-right: 2.75rem; }
/* A round icon button of glass (`.glass`), as the bars: it floats over the text, which scrolls under it. Its own fill
   is the glass's; hovered, a plain fill on it. It keeps clear of the text's scroll bar: of the strip on the right left
   for it (see the fades below), or of the bar itself where it is wider (`--sheet-scrollbar`, sheet.js measures it). */
.sheet-close {
  position: absolute;
  top: var(--alda-space-3);
  right: calc(max(var(--sheet-scrollbar, 0px), var(--alda-space-4)) + var(--alda-space-2));
  z-index: 1;
  width: 2.25rem;
  padding: 0;
  border-radius: 50%;
  background-color: transparent;
  color: var(--alda-ink-dim);
}
.sheet-close:hover:not(:disabled) {
  background-color: var(--alda-fill-hover);
  color: var(--alda-ink);
}
.sheet-close:active:not(:disabled) { background-color: var(--alda-fill-press); }
.sheet-close svg { width: 1rem; height: 1rem; }
/* On a touch screen the scroll bar shows only while the text moves, thin and over it, and is never dragged: the close
   button sits as far in from the side as from the top (further only by a bar that takes room), and the text's fades
   reach the edge. */
@media (pointer: coarse) {
  .sheet-close { right: calc(var(--sheet-scrollbar, 0px) + var(--alda-space-3)); }
  .sheet-body { mask-size: 100% 100%, 0 100%; }
}
@keyframes sheet-in { from { opacity: 0; translate: 0 var(--alda-rise); } }
@keyframes sheet-up { from { translate: 0 100%; } }
@keyframes fade-in { from { opacity: 0; } }
@keyframes sheet-fade-top { from { --fade-top: 0px; } to { --fade-top: var(--alda-space-7); } }
@keyframes sheet-fade-bottom { from { --fade-bottom: var(--alda-space-7); } to { --fade-bottom: 0px; } }
/* The phone's strip of cards fades at its sides, as the sheet's text at its top and bottom (the media query below). */
@property --fade-left { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --fade-right { syntax: "<length>"; inherits: false; initial-value: 0px; }
@keyframes strip-fade-left { from { --fade-left: 0px; } to { --fade-left: var(--alda-space-6); } }
@keyframes strip-fade-right { from { --fade-right: var(--alda-space-6); } to { --fade-right: 0px; } }

/* -------------------------------------------------------------------------------------- phone bar, toast, notice */

/* Download and Share on phones: a capsule of glass over the foot of the page. */
.actionbar {
  position: fixed;
  left: var(--alda-space-2);
  right: var(--alda-space-2);
  bottom: calc(var(--alda-space-2) + env(safe-area-inset-bottom));
  z-index: var(--alda-z-bar);
  display: none;
  align-items: center;
  gap: var(--alda-space-2);
  padding: var(--alda-space-2) var(--alda-space-2) var(--alda-space-2) var(--alda-space-5);
  border-radius: var(--alda-radius-pill);
}
.actionbar button { min-height: var(--alda-control-lg); font-size: var(--alda-text-md); }
.actionbar-text { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.actionbar-text strong, .actionbar-text span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.actionbar-text strong { font-size: var(--alda-text-sm); font-weight: 600; }
.actionbar-text span { color: var(--alda-ink-dim); font-size: var(--alda-text-xs); font-variant-numeric: tabular-nums; }

/* The result of something done in the background: a capsule of glass at the foot of the window, rising as it comes. */
.toast {
  position: fixed;
  left: 50%;
  bottom: var(--alda-space-5);
  z-index: var(--alda-z-toast);
  transform: translateX(-50%);
  width: max-content;
  max-width: min(32rem, calc(100vw - 2rem));
  display: flex;
  align-items: center;
  gap: var(--alda-space-2);
  padding: var(--alda-space-3) var(--alda-space-5) var(--alda-space-3) var(--alda-space-4);
  border-radius: 1.375rem;
  box-shadow: var(--alda-elevation-3);
  color: var(--alda-ink);
  font-size: var(--alda-text-sm);
  font-weight: 500;
  transition: opacity var(--alda-motion-slow) var(--alda-ease);
}
.toast:not([hidden]) { animation: rise-in var(--alda-motion-enter) var(--alda-ease); }
.toast.leaving { opacity: 0; }
/* An icon in the status colour: done, a note, or an error. */
.toast-icon {
  display: none;
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.toast[data-kind="done"] .toast-icon[data-kind="done"] { display: block; color: var(--alda-good); }
.toast[data-kind="note"] .toast-icon[data-kind="note"] { display: block; color: var(--alda-accent); }
.toast[data-kind="error"] .toast-icon[data-kind="error"] { display: block; color: var(--alda-bad); }
@keyframes rise-in { from { opacity: 0; translate: 0 var(--alda-rise); } }

/* An unexpected failure (problems.js): a dialog in the middle of the window, over the dimmed app as the pages' sheet,
   and narrower. It says what failed and offers a report: the user's choice to make, so the app waits behind it. */
.problem {
  width: min(30rem, calc(100% - 2 * var(--alda-space-4)));
  max-width: none;
  max-height: calc(100% - 2 * var(--alda-space-4));
  padding: var(--alda-space-5);
  border: 1px solid var(--alda-border);
  border-radius: var(--alda-radius-dialog);
  background: var(--alda-card);
  box-shadow: var(--alda-elevation-3);
  color: var(--alda-ink);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.problem[open] {
  display: grid;
  gap: var(--alda-space-3);
  animation: sheet-in var(--alda-motion-slow) var(--alda-ease);
}
.problem::backdrop {
  background: var(--alda-scrim);
  -webkit-backdrop-filter: var(--alda-scrim-filter);
  backdrop-filter: var(--alda-scrim-filter);
}
.problem[open]::backdrop { animation: fade-in var(--alda-motion-slow) var(--alda-ease); }
@supports (overlay: auto) {
  .problem, .problem::backdrop {
    transition:
      opacity var(--alda-motion) var(--alda-ease),
      translate var(--alda-motion) var(--alda-ease),
      display var(--alda-motion) allow-discrete,
      overlay var(--alda-motion) allow-discrete;
  }
  .problem:not([open]) { opacity: 0; translate: 0 var(--alda-rise); }
  .problem:not([open])::backdrop { opacity: 0; }
}
.problem p { margin: 0; }
.problem-head { display: flex; align-items: center; gap: var(--alda-space-2); }
.problem-icon {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  fill: none;
  stroke: var(--alda-bad);
  stroke-width: 1.8;
  stroke-linecap: round;
}
.problem h2 { margin: 0; font-size: var(--alda-text-xl); }
/* The title takes the focus as the dialog opens (index.html), without a ring: nothing on it can be pressed. */
.problem h2:focus { outline: none; }
#problem-text { overflow-wrap: anywhere; }
/* What a report holds and where it goes; the report itself; the choice for next time. */
.problem-ask { display: grid; gap: var(--alda-space-3); }
.problem-ask > p, .problem-why { color: var(--alda-ink-dim); font-size: var(--alda-text-sm); }
.problem-more summary {
  width: fit-content;
  color: var(--alda-accent);
  font-size: var(--alda-text-sm);
  font-weight: 600;
  cursor: pointer;
}
.problem-more pre {
  max-height: 14rem;
  overflow: auto;
  margin: var(--alda-space-2) 0 0;
  padding: var(--alda-space-2) var(--alda-space-3);
  border-radius: var(--alda-radius-sm);
  background-color: var(--alda-surface);
  font: var(--alda-text-xs) / 1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.problem-auto { display: flex; align-items: center; gap: var(--alda-space-2); font-size: var(--alda-text-sm); font-weight: 600; }
.problem-auto input { flex: none; width: 1.125rem; height: 1.125rem; margin: 0; accent-color: var(--alda-accent); }
.problem-ask .problem-note {
  margin: calc(-1 * var(--alda-space-2)) 0 0 calc(1.125rem + var(--alda-space-2));
  font-size: var(--alda-text-xs);
}
/* What became of the report. */
.problem-sent { font-weight: 500; }
/* The buttons at the foot, the main one last; the email, as a link, at the start. */
.problem-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--alda-space-2);
  margin-top: var(--alda-space-2);
}
.problem-actions .problem-link { margin-right: auto; }
.problem .problem-link {
  display: inline;
  min-height: 0;
  padding: 0;
  background: none;
  color: var(--alda-accent);
  font: inherit;
  font-size: var(--alda-text-sm);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.problem .problem-link:hover { background: none; color: var(--alda-ink); }
/* The email, where it is the way to report: a link, for its mailto: address, that looks like the main button. */
.problem-report {
  display: inline-flex;
  align-items: center;
  min-height: var(--alda-control);
  padding: 0 var(--alda-space-4);
  border-radius: var(--alda-radius-pill);
  background-color: var(--alda-accent);
  box-shadow: var(--alda-elevation-1);
  color: var(--alda-accent-ink);
  font-size: var(--alda-text-sm);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--alda-motion-fast) var(--alda-ease);
}
.problem-report:hover { background-color: color-mix(in srgb, var(--alda-accent) 86%, var(--alda-ink)); }
/* A phone: the email on its own line, the two buttons sharing the next. */
@media (max-width: 480px) {
  .problem { padding: var(--alda-space-4); }
  .problem-actions .problem-link { flex-basis: 100%; margin-bottom: var(--alda-space-1); }
  .problem-actions > button, .problem-report { flex: 1; justify-content: center; }
}

/* ----------------------------------------------------------------------------------------------------------- phone */

@media (max-width: 860px) {
  :root { --page-gutter: 1rem; }
  .topbar { padding-top: var(--alda-space-2); }
  :root { --topbar-h: calc(var(--alda-space-2) + 3.5rem); }
  .workspace {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "stage" "options" "details";
    grid-template-rows: auto;
    gap: var(--alda-space-3);
    padding: var(--alda-space-3) var(--page-gutter);
  }
  /* The stage keeps the page's margins, with no card: the photo on the page, as wide as the content (stage.js), the
     view capsule above it and in line with it, its shadow not cut off at the stage's edges. */
  .stage-area {
    height: 52vh;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    overflow: visible;
  }
  .busy-overlay { background: color-mix(in srgb, var(--alda-surface) 88%, transparent); }
  /* One row across the stage: the slider takes what the buttons leave. */
  .stage-tools {
    order: 0;
    align-self: stretch;
    flex-wrap: nowrap;
    max-width: none;
    margin: 0;
  }
  .stage-tools .seg { flex: none; }
  .stage-tools .seg button { padding: 0 0.625rem; }
  .zoom { flex: 1 1 0; min-width: 0; padding: 0; }
  .zoom::before { display: none; }
  .zoom input { width: 100%; min-width: 2.5rem; }
  .details { position: static; padding: var(--alda-space-4); }
  .details .actions { display: none; }
  /* The cards scroll sideways to the edge of the screen, and fade out at either side over 2rem where there are more to
     scroll to. The fades grow and shrink with the scrolling, so at either end there is none. Browsers that can't
     animate with scrolling get fixed fades no wider than the strip's padding, which at either end cover only padding. */
  .options {
    --fade-left: var(--alda-space-3);
    --fade-right: var(--alda-space-3);
    flex-wrap: nowrap;
    gap: var(--alda-space-4);
    margin: 0 calc(-1 * var(--alda-space-3));
    padding: 0 var(--alda-space-3) var(--alda-space-2);
    overflow-x: auto;
    scrollbar-width: none;
    mask-image: linear-gradient(to right, transparent, #000 var(--fade-left), #000 calc(100% - var(--fade-right)),
      transparent);
  }
  @supports (animation-timeline: scroll()) {
    .options {
      animation: strip-fade-left linear both, strip-fade-right linear both;
      animation-timeline: scroll(self inline);
      animation-range: 0 var(--alda-space-6), calc(100% - var(--alda-space-6)) 100%;
    }
  }
  .option-group { flex: none; max-width: none; }
  .option-row { flex-wrap: nowrap; padding: 2px 2px 6px; }
  .zoom-label { display: none; }
  body.has-photo .actionbar:not([hidden]) {
    display: flex;
    animation: rise-in var(--alda-motion-enter) var(--alda-ease);
  }
  body.has-photo .toast { bottom: calc(5.5rem + env(safe-area-inset-bottom)); }
  /* The action bar floats over the foot of the page, so the footer keeps clear of it. */
  body.has-photo .site-footer { padding-bottom: calc(6rem + env(safe-area-inset-bottom)); }
  .page { padding: var(--alda-space-4) var(--alda-space-3) var(--alda-space-6); }
  .doc { padding: var(--alda-space-5) var(--alda-space-4); }
  .doc.sections > section { padding: var(--alda-space-4); }
  .sheet .doc.sections { padding: var(--alda-space-4) var(--alda-space-3); }
  .sheet {
    width: 100%;
    max-height: calc(100% - var(--alda-space-6));
    margin: auto 0 0;
    padding-bottom: env(safe-area-inset-bottom);
    border-bottom: 0;
    border-radius: var(--alda-radius-xl) var(--alda-radius-xl) 0 0;
  }
  .sheet[open] { animation: sheet-up var(--alda-motion-enter) var(--alda-ease); }
  /* A handle at the top, as a phone's own sheets have: it can be swiped down (sheet.js). */
  .sheet::before {
    content: '';
    flex: none;
    width: 2.25rem;
    height: 0.3125rem;
    margin: var(--alda-space-2) auto 0;
    border-radius: var(--alda-radius-pill);
    background: color-mix(in srgb, var(--alda-ink) 22%, transparent);
  }
  /* …and goes back down as it closes. */
  @supports (overlay: auto) {
    .sheet { transition-duration: var(--alda-motion-slow); }
    .sheet:not([open]) { opacity: 1; translate: 0 100%; }
  }
}

/* A phone is held and tapped: its type is a size up (body 16 px, labels and controls 15, captions 13), and what is
   pressed is at least 44 px tall, the minimum Apple and Google give for a finger; a segment's choices are 40 within
   their track, and the theme switch's 36 within its own. Most of it follows from the tokens; the rest is sized here. */
@media (max-width: 860px) {
  :root {
    --alda-text-2xs: 0.75rem;
    --alda-text-xs: 0.8125rem;
    --alda-text-sm: 0.9375rem;
    --alda-text-md: 1rem;
    --alda-text-lg: 1.125rem;
    --alda-control-sm: 2.25rem;
    --alda-control: 2.75rem;
    --alda-control-lg: 3rem;
  }
  .topbar-bar { min-height: 3.5rem; padding-top: 0.375rem; padding-bottom: 0.375rem; }
  /* The app's icon as tall as the theme switch's buttons: on a phone it often stands for the name too. */
  .brand-mark { width: 2.25rem; height: 2.25rem; }
  .theme-switch button, .theme-thumb { width: 2.25rem; min-height: 2.25rem; height: 2.25rem; }
  :root[data-pref="system"] .theme-thumb { translate: 2.25rem 0; }
  :root[data-pref="dark"] .theme-thumb { translate: 4.5rem 0; }
  .seg { border-radius: 1.4375rem; }
  .seg button { min-height: 2.5rem; }
  .stage-tools { border-radius: 1.6875rem; }
  .zoom input { height: 2.75rem; }
  .zoom input::-webkit-slider-runnable-track { height: 6px; }
  .zoom input::-moz-range-track, .zoom input::-moz-range-progress { height: 6px; }
  .zoom input::-webkit-slider-thumb { width: 24px; height: 24px; margin-top: -9px; }
  .zoom input::-moz-range-thumb { width: 24px; height: 24px; }
  .switch-row input { width: 3.25rem; height: 2rem; }
  .switch-row input::before { width: 1.75rem; height: 1.75rem; }
  .switch-row input:checked::before { transform: translateX(1.25rem); }
  .size-seg button { min-height: 3.25rem; }
  .thumb .badge { font-size: 0.75rem; line-height: 1.25rem; }
  .sheet-close { width: 2.75rem; }
  .site-footer nav { flex-wrap: wrap; justify-content: center; column-gap: var(--alda-space-4); row-gap: 0; }
  .site-footer a { padding: var(--alda-space-3) 0; }
}
/* Sora runs wider than the system's font: on a narrow phone the five links stand closer, to stay on one row. */
@media (max-width: 30rem) { .site-footer nav { column-gap: 0.625rem; } }

@media (max-width: 640px) {
  .photo-info { display: none; }
  /* The steps one under another, each number beside its words. */
  .doc .steps { grid-template-columns: minmax(0, 1fr); }
  .doc .steps > li { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: var(--alda-space-3); }
  .doc .steps > li::before { grid-row: span 2; margin: 0; }
}

/* A narrow phone: the top bar keeps to one line. With a photo open, New photo and the theme switch need the room, and
   the mark stands for the name, which screen readers still read. */
@media (max-width: 480px) {
  .topbar-bar { gap: var(--alda-space-2); }
  #new-photo { padding: 0 var(--alda-space-3); }
  body.has-photo .brand-name {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* Reduced motion: the sheet and the problem dialog fade in and out rather than rising and sinking. */
@media (prefers-reduced-motion: reduce) {
  .sheet[open], .problem[open] { animation-name: fade-in; }
  .sheet:not([open]), .problem:not([open]) { opacity: 0; translate: none; }
}

/* Windows' high contrast: every pane and control keeps an outline in the system's colours. */
@media (forced-colors: active) {
  .glass, .details, .doc, .sheet, .problem, .option, .drop, button, .problem-report, .doc a.mail, a.go {
    border: 1px solid CanvasText;
  }
  .glass::before, .glass::after { display: none; }
  .option[aria-pressed="true"], .seg button[aria-pressed="true"] { outline: 2px solid Highlight; }
  .switch-row input { border: 1px solid CanvasText; }
  .switch-row input:checked { background-color: Highlight; }
  /* The system draws the slider, as the drawn rail and knob lose their colours. */
  .zoom input { -webkit-appearance: auto; appearance: auto; }
  .theme-thumb { display: none; }
  .theme-switch button[aria-pressed="true"] { outline: 2px solid Highlight; }
}
