**Cross-references can name a section.** `[[264#workup|the workup]]` opens the reader at that heading, which is what a sentence about one part of a long article actually means. Whole-article `[[264|label]]` is unchanged, and a section renamed since is not a broken link — it lands at the top of the right article, which is a mild disappointment rather than a dead end. **A picker that writes the marker for you.** 🔗 Link an article, in the editor: type a few words, click the article — or one of its sections — and the marker is on the clipboard with the right title as its label. Getting an id used to mean opening the library in another tab, finding the article and reading the number out of the address bar, which is four steps and a chance to mistype, every time. Its own small endpoint, because the listing deliberately does not carry sections and this needs nothing else. **Three things about cards that were built but never drawn:** - A card can carry an image. The column is there, the API returns it, the editor accepts one — and no view in the app rendered it, so every picture anybody attached to a card was stored and never seen. Both card views show it now, small until clicked like every other figure. - The deck browser printed `[[331|Epiglottitis]]` as brackets and a number. The study view has rendered them as links for a while; now both do. - There was no way to make a deck by hand. Every deck came out of a model — generated from a document section or an article — so an educator who wanted to write six cards had nowhere to put them, and the add-a-card route could only add to a deck that did not exist yet. `+ New deck` on the cards page. **Generate cards ran in silence.** It starts a real job, and the only place its progress was drawn was inside the refine panel — which lives in the editor and is shut. Pressing it on the reading page did nothing visible for ninety seconds. It now says what it is doing where it was pressed. **Overlays were invisible to learners.** A stored width is a fraction of the image, and the stroke is drawn with `non-scaling-stroke`, which makes `stroke-width` a count of screen pixels — so 0.006 meant six thousandths of a pixel. The editor has always multiplied by its rendered width; the viewer now does the same sum. Every region an educator has ever marked was invisible to everyone who was not editing it. Also: the figure viewer no longer scrolls, at any width, and the page behind it is pinned properly (`overflow: hidden` on the body does nothing on iOS, so a figure opened half-way down an article drifted while it was read). Options are full width on a phone. The question toolbar's seven glyphs are four, with the rest folded into the ⋯ that was already there, spelled out in words. The jobs popover closes on a click anywhere outside it. And the editor has a way back to Editorial — "back to the article", from an article you opened to edit, is a loop. The contract snapshot caught both new routes on the way through, which is what it is for. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
105 lines
5.3 KiB
CSS
105 lines
5.3 KiB
CSS
/* Small until asked for. The caption is the author's own alt text, so what a
|
|
reader sees under the figure and what a screen reader is told are the same
|
|
sentence — and there is no second field to keep in step with the first. */
|
|
.imgfig { display: inline-flex; flex-direction: column; gap: 5px; margin: 10px 12px 10px 0; vertical-align: top; max-width: 100%; }
|
|
.imgfig-thumb {
|
|
display: block; padding: 0; cursor: zoom-in; line-height: 0;
|
|
border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
|
|
background: var(--card-bg);
|
|
}
|
|
.imgfig-thumb:hover { border-color: var(--primary); }
|
|
.imgfig-thumb img { display: block; max-width: 260px; max-height: 200px; width: auto; height: auto; }
|
|
.imgfig-thumb.is-vector { width: min(100%, 260px); }
|
|
.imgfig-thumb.is-vector img { width: 100%; height: auto; }
|
|
.imgfig-label { max-width: 260px; font-size: 0.78rem; line-height: 1.4; color: var(--text-muted); }
|
|
|
|
/* ── The viewer ───────────────────────────────────────────────────────
|
|
The image gets the screen, and what is known about it sits beside it. Dark,
|
|
because a radiograph read against a white page is read through glare. */
|
|
.imgfig-viewer {
|
|
position: fixed; inset: 0; z-index: 1200;
|
|
display: flex; flex-direction: column;
|
|
background: #0b1220; color: #e2e8f0;
|
|
/* The viewer never scrolls as a whole, at any width. It is one screen: look
|
|
at the picture, close it, carry on from where you were. A scrollbar down
|
|
the side of it invites a scroll that moves nothing anybody wanted moved. */
|
|
overflow: hidden;
|
|
}
|
|
.imgfig-bar {
|
|
display: flex; align-items: center; gap: 10px;
|
|
padding: 10px 14px; border-bottom: 1px solid rgba(255, 255, 255, .1);
|
|
}
|
|
.imgfig-tool {
|
|
display: inline-flex; align-items: center; gap: 7px;
|
|
padding: 6px 13px; cursor: pointer; font: inherit; font-size: 0.83rem; font-weight: 600;
|
|
border: 1px solid rgba(255, 255, 255, .22); border-radius: 8px;
|
|
background: transparent; color: #e2e8f0;
|
|
}
|
|
.imgfig-tool:hover { border-color: #5eead4; color: #5eead4; }
|
|
.imgfig-tool.is-on { border-color: #5eead4; color: #0b1220; background: #5eead4; }
|
|
.imgfig-close {
|
|
margin-left: auto; width: 34px; height: 34px; cursor: pointer;
|
|
border: 0; border-radius: 8px; background: transparent; color: #e2e8f0; font-size: 1rem;
|
|
}
|
|
.imgfig-close:hover { background: rgba(255, 255, 255, .12); }
|
|
|
|
.imgfig-body {
|
|
flex: 1; min-height: 0; overflow: hidden;
|
|
display: grid; grid-template-columns: 320px minmax(0, 1fr);
|
|
}
|
|
.imgfig-desc {
|
|
display: flex; flex-direction: column; gap: 14px;
|
|
padding: 26px 24px; overflow-y: auto;
|
|
border-right: 1px solid rgba(255, 255, 255, .1);
|
|
}
|
|
.imgfig-desc strong { font-size: 1.05rem; font-weight: 700; }
|
|
.imgfig-desc-text { font-size: 0.92rem; line-height: 1.6; color: #cbd5e1; }
|
|
.imgfig-source { font-size: 0.78rem; line-height: 1.55; color: #94a3b8; }
|
|
.imgfig-source a { color: #94a3b8; }
|
|
|
|
.imgfig-stage {
|
|
display: flex; align-items: center; justify-content: center;
|
|
/* `hidden`, not `auto`: the picture is capped to the space it has, so there
|
|
is nothing to scroll to. */
|
|
padding: 20px; overflow: hidden; cursor: zoom-out;
|
|
min-height: 0;
|
|
}
|
|
/* The frame is what the overlay is positioned against, so it must be exactly
|
|
the size of the drawn image and no larger — hence a block that shrinks to
|
|
its content rather than a flex child that stretches. */
|
|
.imgfig-frame { position: relative; display: block; line-height: 0; cursor: default; }
|
|
.imgfig-frame { max-width: 100%; max-height: 100%; }
|
|
.imgfig-frame img { display: block; max-width: 100%; max-height: 100%; width: auto; height: auto; }
|
|
/* A drawing has no size of its own, only a shape, so it is given the width it
|
|
is allowed and takes its height from that. Line art scales; a photograph
|
|
would be blown up by the same rule, which is why this is not the default. */
|
|
.imgfig-frame.is-vector { width: min(100%, 900px); }
|
|
.imgfig-frame.is-vector img { width: 100%; height: auto; max-height: 100%; object-fit: contain; }
|
|
.imgov { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
|
|
|
|
@media (max-width: 820px) {
|
|
/* Stacked, description first: it can be read before scrolling to the
|
|
picture rather than after it, and on a phone the picture wants the width
|
|
more than the text does. */
|
|
/* The viewer fills the screen and does not scroll as a whole. What the
|
|
picture is stays at the top and scrolls inside its own box if it is long;
|
|
the picture keeps everything under it. A viewer you have to scroll to see
|
|
the picture in is a viewer that looks broken. */
|
|
.imgfig-body { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); overflow: hidden; }
|
|
.imgfig-desc {
|
|
border-right: 0; border-bottom: 1px solid rgba(255, 255, 255, .1);
|
|
padding: 16px 16px 14px; gap: 10px;
|
|
max-height: 38dvh; overflow-y: auto;
|
|
}
|
|
.imgfig-stage { padding: 12px; }
|
|
.imgfig-frame img { max-height: 100%; }
|
|
/* Stacked, so the picture has the width of the screen and whatever height
|
|
its shape asks for — the row it sits in scrolls with the description. */
|
|
.imgfig-frame.is-vector { width: 100%; }
|
|
.imgfig-frame.is-vector img { max-height: 100%; }
|
|
}
|
|
|
|
@media (max-width: 560px) {
|
|
.imgfig { margin-right: 0; }
|
|
.imgfig-thumb img, .imgfig-label { max-width: 100%; }
|
|
}
|