Reading is read-only. Edit, Unpublish and Generate cards sat in the reading toolbar, so an educator reading between questions was one mis-tap from the editor — which is how somebody opened edit mode on Bronchiolitis in the middle of a session. All three live at /editorial/articles/:id now, with one named door through from Reading for whoever may edit. An ?edit=1 on a reading address is not ignored: the ask is fine, the address is wrong, so it is taken to the editorial one. And a cross-reference followed from Editorial stays in Editorial. Reading and Editorial are two modes of the same page, and one link out of the second into the first put an educator into the learner's view of the next article with no way back to the queue. The menu button now reaches the menu on every page it has been taken over on. On a phone the burger belongs to whatever is on screen; the player handed back the site menu as a tab inside its drawer, and an article and an answer review did not — so on those two the only menu button on the page could not open the menu. Both have the player's own two tabs now, from one list of links rather than three copies of it (one of which pointed Qbank at /questions, which has never been a route). And the button shows a cross while what it opens is open. It kept its three bars behind an open drawer, an inch from the cross inside that drawer: two controls disagreeing about what was on screen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
547 lines
31 KiB
CSS
547 lines
31 KiB
CSS
.articles-page, .article-page { max-width: 1080px; margin: 0 auto; padding: 4px 0 24px; }
|
|
.articles-header { display: flex; justify-content: space-between; align-items: flex-end; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
|
|
.articles-header h1, .article-header h1 { margin: 0 0 4px; font-size: 1.5rem; }
|
|
.articles-subtitle { margin: 0; color: var(--text-muted); font-size: 0.88rem; }
|
|
.articles-toolbar { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
|
|
.articles-toolbar .input { max-width: 320px; }
|
|
.articles-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }
|
|
.article-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--card-radius); padding: 16px; text-decoration: none; color: var(--text); transition: box-shadow .15s ease, transform .15s ease; }
|
|
.article-card:hover { box-shadow: 0 8px 24px rgba(2, 70, 145, .12); transform: translateY(-2px); }
|
|
.article-card h3 { margin: 0 0 6px; font-size: 1.02rem; }
|
|
.article-card p { margin: 0 0 8px; color: var(--text-muted); font-size: .85rem; }
|
|
.article-card-meta { color: var(--text-muted); font-size: .75rem; }
|
|
.article-status-draft { font-size: .65rem; font-weight: 700; text-transform: uppercase; color: #92400e; background: #fef3c7; padding: 2px 7px; border-radius: 10px; margin-left: 6px; vertical-align: middle; }
|
|
.breadcrumbs { font-size: .8rem; color: var(--text-muted); margin-bottom: 8px; }
|
|
.breadcrumbs a { color: var(--primary); text-decoration: none; }
|
|
.article-header { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
|
|
.article-header-actions { display: flex; gap: 8px; }
|
|
/* ── The reading layout ───────────────────────────────────────────────
|
|
Rail flush to the left edge of the window, prose taking everything to the
|
|
right of it. `--article-top` is the measured height of the site header, set
|
|
by the reader: the navbar's strip collapses as you scroll, and a number
|
|
written down here would go stale the moment that changes. */
|
|
|
|
.app-main.is-bleed { width: 100%; padding: 0; }
|
|
/* The navbar keeps 32px of air beneath it for pages that are cards on a
|
|
background. A reading page is not one — the rail and the article run to the
|
|
window edges, and a band of page showing above them reads as a gap where
|
|
something failed to load. */
|
|
.article-page.is-reading { max-width: none; margin: -32px 0 0; padding: 0; }
|
|
.article-notices { max-width: 1080px; margin: 0 auto; padding: 12px 28px 0; }
|
|
|
|
.article-layout {
|
|
--article-top: 98px;
|
|
display: grid;
|
|
grid-template-columns: 272px minmax(0, 1fr);
|
|
align-items: start;
|
|
}
|
|
/* A rail, not a card: the contents of a long article should stay in view for
|
|
its whole length, scrolling on their own when there are more sections than
|
|
screen. It keeps its own scroll so the page behind it never moves. */
|
|
.article-sections {
|
|
position: sticky;
|
|
top: var(--article-top);
|
|
height: calc(100dvh - var(--article-top));
|
|
/* The collapse handle hangs over the boundary, so nothing here may clip. */
|
|
overflow: visible;
|
|
background: var(--bg);
|
|
border-right: 1px solid var(--border);
|
|
}
|
|
.article-rail-scroll { height: 100%; overflow-y: auto; padding: 16px 12px 28px 20px; }
|
|
.article-sections h4 { margin: 0 0 10px; font-size: .82rem; font-weight: 700; line-height: 1.35; color: var(--text); }
|
|
|
|
/* Collapsing it hands the width to the prose, which is what a long table or a
|
|
wide image needs and what nothing else on the page can give it. Remembered
|
|
between articles, because it is a statement about how you read. */
|
|
.article-layout.is-railed-off { grid-template-columns: 30px minmax(0, 1fr); }
|
|
.article-layout.is-railed-off .article-sections { display: none; }
|
|
|
|
.article-rail-hide, .article-rail-reopen {
|
|
display: flex; align-items: center; justify-content: center;
|
|
width: 26px; height: 26px; padding: 0;
|
|
background: var(--card-bg); border: 1px solid var(--border); border-radius: 50%;
|
|
color: var(--text-muted); font: inherit; font-size: 1rem; line-height: 1; cursor: pointer;
|
|
}
|
|
.article-rail-hide:hover, .article-rail-reopen:hover { border-color: var(--primary); color: var(--primary); }
|
|
/* On the boundary between the rail and the prose — where the reader is looking
|
|
when they decide they want the width. */
|
|
.article-rail-hide { position: absolute; top: 16px; right: -13px; z-index: 3; }
|
|
/* And where the rail was, so putting it back is where you last saw it. */
|
|
.article-rail-reopen { position: sticky; top: calc(var(--article-top) + 16px); margin: 16px 0 0 2px; }
|
|
|
|
.article-sections ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
|
|
.section-link { width: 100%; text-align: left; background: none; border: none; border-radius: 6px; padding: 7px 10px; font-size: .84rem; line-height: 1.4; color: var(--text); cursor: pointer; }
|
|
.section-link:hover { background: var(--hover, #eef4fb); }
|
|
.section-link.active { background: var(--primary-soft, #dcebfa); color: var(--primary); font-weight: 600; }
|
|
|
|
.article-content {
|
|
min-width: 0;
|
|
background: var(--card-bg);
|
|
padding: 14px clamp(20px, 3.5vw, 56px) 48px;
|
|
min-height: calc(100dvh - var(--article-top));
|
|
}
|
|
.article-content h2 { margin-top: 0; }
|
|
.article-content img { max-width: 100%; border-radius: 8px; }
|
|
.article-content table { border-collapse: collapse; width: 100%; margin: 12px 0; }
|
|
.article-content td, .article-content th { border: 1px solid var(--border); padding: 6px 10px; }
|
|
|
|
/* Three steps, because a reader wants bigger or smaller and nothing finer. */
|
|
.article-text-s { font-size: .92rem; }
|
|
.article-text-m { font-size: 1rem; }
|
|
.article-text-l { font-size: 1.12rem; }
|
|
|
|
/* The icon toolbar sits above the title, opposite the trail back to the
|
|
library — the two things you do with an article that are not reading it. */
|
|
.article-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding-top: 10px; }
|
|
.article-trail { min-width: 0; }
|
|
.article-trail .breadcrumbs { margin-bottom: 0; }
|
|
.article-tools { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
|
|
.article-tool {
|
|
display: inline-flex; align-items: baseline; justify-content: center; gap: 1px;
|
|
min-width: 32px; height: 32px; padding: 0 8px;
|
|
background: none; border: 1px solid var(--border); border-radius: 8px;
|
|
font: inherit; font-size: .95rem; line-height: 1; color: var(--text-muted); cursor: pointer;
|
|
}
|
|
.article-tool:hover { border-color: var(--primary); color: var(--primary); }
|
|
.article-tool.is-on { border-color: var(--primary); color: var(--primary); background: var(--primary-soft, #dcebfa); }
|
|
.article-tool-a { font-size: .72rem; }
|
|
|
|
.article-title { margin: 6px 0 0; font-size: 1.75rem; line-height: 1.2; }
|
|
.article-updated { font-size: .76rem; color: var(--text-subtle); margin: 8px 0 0; }
|
|
.article-summary { font-size: .95em; color: var(--text-muted); border-left: 3px solid var(--primary); padding-left: 12px; margin: 14px 0 4px; }
|
|
.article-summary p:last-child { margin-bottom: 0; }
|
|
|
|
/* Contents on a narrow screen, where there is no room for a rail beside prose. */
|
|
.article-drawer-toggle {
|
|
display: none; align-items: center; gap: 6px; height: 32px; padding: 0 12px;
|
|
background: var(--card-bg); border: 1px solid var(--border); border-radius: 8px;
|
|
font: inherit; font-size: .82rem; color: var(--text); cursor: pointer;
|
|
}
|
|
.article-linked { margin-top: 22px; border-top: 1px solid var(--border); padding-top: 14px; }
|
|
.article-linked h3 { margin: 0 0 10px; font-size: 1rem; }
|
|
.linked-card { display: flex; justify-content: space-between; align-items: center; gap: 10px; border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; margin-bottom: 8px; flex-wrap: wrap; }
|
|
.article-edit { display: flex; flex-direction: column; gap: 8px; }
|
|
.article-edit .form-label { margin-top: 6px; }
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.article-sections { transition: none !important; }
|
|
}
|
|
|
|
@media (max-width: 820px) {
|
|
/* No room for a rail beside prose. The contents become a panel over the
|
|
page, opened from the article's own bar — the site menu stays on the
|
|
navbar's button, so the two never compete for the same thumb. */
|
|
.article-layout, .article-layout.is-railed-off { grid-template-columns: minmax(0, 1fr); }
|
|
.article-sections {
|
|
position: fixed;
|
|
top: var(--article-top); bottom: 0; left: 0;
|
|
/* Above the split pane and above an open figure: the menu is pressed from
|
|
the header, which is on top of both, so a drawer that opened behind them
|
|
looked like a button that did nothing. */
|
|
z-index: 1250;
|
|
width: min(320px, 86vw);
|
|
height: auto;
|
|
transform: translateX(-101%);
|
|
/* Hidden rather than merely off-screen: a panel parked past the left edge
|
|
is still in the tab order, and tabbing into contents you cannot see is
|
|
how a keyboard reader loses the page. */
|
|
visibility: hidden;
|
|
border-right: 1px solid var(--border);
|
|
box-shadow: 8px 0 28px rgba(15, 23, 42, .18);
|
|
transition: transform .18s ease, visibility .18s;
|
|
}
|
|
.article-sections.open { transform: none; visibility: visible; }
|
|
/* The drawer's own head: the way out, and the two things behind this
|
|
button. The same shape the session player's drawer has, because it is
|
|
the same button — on a phone the burger belongs to whatever is on
|
|
screen, and the site menu is a tab inside it. Reading had only the
|
|
contents, so the menu button on an article could not reach the menu. */
|
|
.article-drawer-head {
|
|
display: flex; align-items: center; gap: 10px;
|
|
padding: 10px 12px; border-bottom: 1px solid var(--border); flex: none;
|
|
}
|
|
.article-drawer-close {
|
|
flex: none; width: 34px; height: 34px;
|
|
background: none; border: 0; border-radius: 8px;
|
|
font-size: 1rem; cursor: pointer; color: var(--text-muted);
|
|
}
|
|
.article-drawer-tabs {
|
|
display: flex; flex: 1; border: 1px solid var(--border);
|
|
border-radius: 8px; overflow: hidden;
|
|
}
|
|
.article-drawer-tabs button {
|
|
flex: 1; padding: 9px 6px; min-height: 40px;
|
|
font: inherit; font-size: .84rem; font-weight: 600;
|
|
background: var(--card-bg); border: 0; cursor: pointer; color: var(--text-muted);
|
|
}
|
|
.article-drawer-tabs button[aria-selected="true"] {
|
|
background: var(--option-sel-bg); color: var(--primary);
|
|
}
|
|
.article-drawer-menu { display: flex; flex-direction: column; padding: 6px; overflow-y: auto; }
|
|
.article-drawer-menu a {
|
|
padding: 12px 10px; min-height: 44px;
|
|
font-size: .9rem; text-decoration: none; color: var(--text); border-radius: 8px;
|
|
}
|
|
.article-drawer-menu a:hover { background: var(--bg); }
|
|
/* The dark ground behind an open drawer. Tapping it closes the drawer. */
|
|
.article-drawer-backdrop {
|
|
/* Below the header, not over it. Covering the header put a transparent
|
|
sheet across the very button that opened the drawer, so pressing it
|
|
again hit the backdrop instead — the drawer closed, but the button
|
|
looked dead. */
|
|
position: fixed; top: var(--article-top); left: 0; right: 0; bottom: 0;
|
|
z-index: 1249; background: rgba(15, 23, 42, .38);
|
|
}
|
|
.article-rail-hide, .article-rail-reopen { display: none; }
|
|
/* No Contents button. The menu in the header opens the contents on a phone,
|
|
and it is the control that is in the same place on every page — a second
|
|
one in the prose is the same door twice, which is what the quiz player had
|
|
until it did not. */
|
|
.article-drawer-toggle { display: none; }
|
|
.article-content { padding: 12px 16px 40px; min-height: 0; }
|
|
.article-title { font-size: 1.4rem; }
|
|
}
|
|
.comment-section { margin-top: 22px; border-top: 1px solid var(--border); padding-top: 14px; }
|
|
.comment-heading { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
|
|
.comment-heading h3 { margin: 0; font-size: 1rem; }
|
|
.comment-subtitle { font-size: .74rem; color: var(--text-muted); }
|
|
.comment-compose { background: var(--input-bg); border: 1px solid var(--border); border-radius: 10px; padding: 10px; margin-bottom: 14px; }
|
|
.comment-input { width: 100%; border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; font-size: .88rem; resize: vertical; }
|
|
.comment-compose-footer { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
|
|
.comment-count { margin-left: auto; font-size: .72rem; color: var(--text-muted); }
|
|
.comment-empty { color: var(--text-muted); font-size: .84rem; margin: 6px 0 0; }
|
|
.comment-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
|
|
.comment { display: flex; gap: 10px; padding: 12px; border: 1px solid var(--border); border-radius: 10px; background: var(--card-bg); }
|
|
.comment-avatar { width: 30px; height: 30px; border-radius: 50%; background: var(--primary-soft, #dcebfa); color: var(--primary); font-weight: 700; display: flex; align-items: center; justify-content: center; font-size: .9rem; flex-shrink: 0; }
|
|
.comment-body { flex: 1; min-width: 0; }
|
|
.comment-meta { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 4px; font-size: .84rem; }
|
|
.comment-meta span { color: var(--text-muted); font-size: .74rem; }
|
|
.comment-badge { font-style: normal; font-size: .66rem; font-weight: 700; text-transform: uppercase; color: #92400e; background: #fef3c7; padding: 1px 8px; border-radius: 10px; }
|
|
.comment-content { font-size: .88rem; }
|
|
.comment-content p { margin: 0 0 4px; }
|
|
.comment-actions { display: flex; gap: 6px; margin-top: 8px; }
|
|
.comment-load-more { margin-top: 10px; }
|
|
.comment-section { margin-top: 22px; border-top: 1px solid var(--border); padding-top: 14px; }
|
|
.comment-heading { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
|
|
.comment-heading h3 { margin: 0; font-size: 1rem; }
|
|
.comment-subtitle { font-size: .74rem; color: var(--text-muted); }
|
|
.comment-compose { background: var(--input-bg); border: 1px solid var(--border); border-radius: 10px; padding: 10px; margin-bottom: 14px; }
|
|
.comment-input { width: 100%; border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; font-size: .88rem; resize: vertical; }
|
|
.comment-compose-footer { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
|
|
.comment-count { margin-left: auto; font-size: .72rem; color: var(--text-muted); }
|
|
.comment-empty { color: var(--text-muted); font-size: .84rem; margin: 6px 0 0; }
|
|
.comment-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
|
|
.comment { display: flex; gap: 10px; padding: 12px; border: 1px solid var(--border); border-radius: 10px; background: var(--card-bg); }
|
|
.comment-avatar { width: 30px; height: 30px; border-radius: 50%; background: var(--primary-soft, #dcebfa); color: var(--primary); font-weight: 700; display: flex; align-items: center; justify-content: center; font-size: .9rem; flex-shrink: 0; }
|
|
.comment-body { flex: 1; min-width: 0; }
|
|
.comment-meta { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 4px; font-size: .84rem; }
|
|
.comment-meta span { color: var(--text-muted); font-size: .74rem; }
|
|
.comment-badge { font-style: normal; font-size: .66rem; font-weight: 700; text-transform: uppercase; color: #92400e; background: #fef3c7; padding: 1px 8px; border-radius: 10px; }
|
|
.comment-content { font-size: .88rem; }
|
|
.comment-content p { margin: 0 0 4px; }
|
|
.comment-actions { display: flex; gap: 6px; margin-top: 8px; }
|
|
.comment-load-more { margin-top: 10px; }
|
|
@keyframes article-slide-in { from { transform: translateX(24px); opacity: 0; } to { transform: none; opacity: 1; } }
|
|
|
|
/* ── Practise this topic ──────────────────────────────────────────── */
|
|
.article-practise { margin-top: 22px; border-top: 1px solid var(--border); padding-top: 16px; }
|
|
.article-practise-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
|
|
.article-practise-head h3 { margin: 0; font-size: 1rem; }
|
|
.article-practise-count { font-size: .78rem; color: var(--text-muted); }
|
|
.article-practise-empty { color: var(--text-muted); font-size: .86rem; margin: 0; }
|
|
.article-practise-controls { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
|
|
.article-practise-controls label { display: flex; flex-direction: column; gap: 4px; }
|
|
.article-practise-controls label span { font-size: .68rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-subtle); }
|
|
.article-practise-controls select {
|
|
padding: 8px 11px; border: 1px solid var(--border); border-radius: 8px;
|
|
background: var(--input-bg); color: var(--text); font-size: .88rem;
|
|
}
|
|
.article-practise-error { color: var(--wrong-fg); font-size: .84rem; margin: 8px 0 0; }
|
|
.article-practise-manage { margin-top: 14px; }
|
|
.article-practise-manage > button {
|
|
background: none; border: none; padding: 0; cursor: pointer; font: inherit;
|
|
font-size: .78rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted);
|
|
}
|
|
.article-practise-manage > button:hover { color: var(--primary); }
|
|
.article-practise-manage ul { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
|
|
.article-practise-manage li {
|
|
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
|
|
border: 1px solid var(--border); border-radius: 8px; padding: 9px 11px; font-size: .85rem;
|
|
}
|
|
.article-practise-manage li span { flex: 1; min-width: 140px; overflow-wrap: anywhere; }
|
|
.article-practise-manage li em { font-size: .72rem; color: var(--text-muted); font-style: normal; }
|
|
|
|
@media (max-width: 640px) {
|
|
.article-practise-controls { align-items: stretch; }
|
|
.article-practise-controls label { flex: 1; }
|
|
.article-practise-controls .btn { width: 100%; }
|
|
}
|
|
|
|
|
|
/* Category browser on the articles page */
|
|
.articles-browse {
|
|
display: inline-flex; align-items: center; gap: 8px; min-height: 42px;
|
|
padding: 9px 14px; background: var(--card-bg); border: 1px solid var(--border);
|
|
border-radius: 8px; font: inherit; font-size: .88rem; color: var(--text); cursor: pointer;
|
|
}
|
|
.articles-browse:hover { border-color: var(--primary); color: var(--primary); }
|
|
.articles-browse[aria-expanded='true'] { border-color: var(--primary); color: var(--primary); }
|
|
.articles-browser { margin-bottom: 16px; }
|
|
|
|
/* ── Collapsible sections ─────────────────────────────────────────────
|
|
An article is a reference you consult, so it opens as a contents page:
|
|
headings only, each expanding where it sits. */
|
|
|
|
/* The row above the sections. It parks under the site header as you read, so
|
|
the depth switch and the expand control stay reachable and the trail can say
|
|
where in the article you have got to once the title has scrolled away. */
|
|
.asec-controls {
|
|
position: sticky;
|
|
top: var(--article-top);
|
|
z-index: 12;
|
|
display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
|
|
margin: 16px 0 0;
|
|
padding: 8px 0;
|
|
background: var(--card-bg);
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
.asec-controls-left, .asec-controls-right { display: flex; align-items: center; gap: 10px; min-width: 0; }
|
|
/* Where you are, once the heading has gone: article, then the section under
|
|
the reader's eye — the same one the rail marks. */
|
|
.asec-where { min-width: 0; font-size: .8rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.asec-where-section { color: var(--text); font-weight: 600; }
|
|
|
|
.asec-list { border-top: 1px solid var(--border); }
|
|
.asec { scroll-margin-top: calc(var(--article-top, 98px) + 56px); border-bottom: 1px solid var(--border); }
|
|
.asec-heading { margin: 0; font-size: 1rem; }
|
|
|
|
.asec-head {
|
|
display: flex; align-items: center; gap: 12px; width: 100%;
|
|
min-height: 52px; padding: 13px 4px 13px 8px;
|
|
background: none; border: 0; border-radius: 8px;
|
|
font: inherit; font-size: 1rem; font-weight: 700; color: var(--text);
|
|
text-align: left; cursor: pointer;
|
|
}
|
|
.asec-head:hover { background: var(--bg); }
|
|
.asec-head:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
|
|
.asec-title { flex: 1; min-width: 0; overflow-wrap: anywhere; }
|
|
.asec-chevron {
|
|
flex-shrink: 0; font-size: 1.1rem; line-height: 1; color: var(--text-muted);
|
|
transition: transform 0.16s ease;
|
|
}
|
|
.asec-head[aria-expanded='true'] .asec-chevron { transform: rotate(180deg); }
|
|
|
|
/* `em`, not `rem`: the text-size control sets a size on the article and the
|
|
prose inside it has to follow. */
|
|
.asec-body { padding: 0 8px 18px; font-size: 0.95em; line-height: 1.65; }
|
|
.asec-body > :first-child { margin-top: 0; }
|
|
|
|
/* A sub-section is drawn inside its parent, indented and quieter, so the
|
|
hierarchy is visible without a second heading level shouting. */
|
|
.asec-depth-1 { margin: 10px 0 0 4px; border-left: 2px solid var(--border); border-bottom: 0; padding-left: 10px; }
|
|
.asec-depth-1 .asec-head { min-height: 44px; font-size: 0.92rem; font-weight: 600; padding: 10px 4px 10px 6px; }
|
|
.asec-depth-1 .asec-body { padding-bottom: 10px; }
|
|
|
|
.asec.is-target > .asec-heading > .asec-head { box-shadow: inset 3px 0 0 var(--primary); color: var(--primary); }
|
|
.asec.is-references .asec-body { font-size: 0.86rem; color: var(--text-muted); }
|
|
|
|
/* Contents list, with sub-sections under the section they belong to. */
|
|
.atoc-sub { margin: 2px 0 4px 10px !important; padding-left: 8px !important; border-left: 1px solid var(--border); }
|
|
.atoc-sub .section-link { font-size: 0.8rem; color: var(--text-muted); }
|
|
.atoc-sub .section-link.active { color: var(--primary); }
|
|
|
|
@media (max-width: 640px) {
|
|
.asec-head { font-size: 0.95rem; }
|
|
.asec-body { font-size: 0.92rem; }
|
|
}
|
|
|
|
/* One topic, three readings — at the right of the row over the sections. The
|
|
rail is filtered by the same choice, so the contents can never list a
|
|
section the body is no longer showing. */
|
|
.aview-group { display: inline-flex; align-items: center; gap: 10px; }
|
|
|
|
/* Summary is a toggle, not a tab: it is the whole topic or the part of it
|
|
worth revising, and it names its own state so a reader can tell at a glance
|
|
why two thirds of the contents are not there. */
|
|
.aview-only {
|
|
display: inline-flex; align-items: center; gap: 8px;
|
|
min-height: 36px; padding: 7px 14px; cursor: pointer;
|
|
font: inherit; font-size: 0.83rem; font-weight: 600;
|
|
color: var(--text-muted); background: var(--card-bg);
|
|
border: 1px solid var(--border); border-radius: 8px;
|
|
}
|
|
.aview-only span { font-size: 0.95rem; line-height: 1; }
|
|
.aview-only:hover { color: var(--text); border-color: var(--text-subtle); }
|
|
.aview-only.is-on {
|
|
color: var(--primary); border-color: var(--primary);
|
|
background: color-mix(in srgb, var(--primary) 8%, transparent);
|
|
}
|
|
|
|
/* Six pixels, not two. At two the selected tab's fill ran straight into the
|
|
one beside it and the pair read as one wide control with a coloured half. */
|
|
.aview-switch { display: inline-flex; gap: 6px; padding: 3px; background: var(--bg); border: 1px solid var(--border); border-radius: 9px; }
|
|
.aview {
|
|
min-height: 34px; padding: 6px 13px; border: 0; border-radius: 7px; cursor: pointer;
|
|
background: none; font: inherit; font-size: 0.83rem; font-weight: 600; color: var(--text-muted);
|
|
}
|
|
.aview:hover { color: var(--text); }
|
|
/* Loud on purpose: this is the control that decides how much of the topic is
|
|
on screen, and a reader who cannot see which way it is set cannot explain
|
|
why two thirds of the contents just went away. */
|
|
.aview.is-active {
|
|
background: var(--primary); color: #fff;
|
|
box-shadow: 0 1px 3px rgba(15, 23, 42, .22);
|
|
}
|
|
.aview.is-active:hover { color: #fff; }
|
|
|
|
/* Sources for the whole article, not markers scattered through the prose. */
|
|
.article-references { margin-top: 26px; padding-top: 14px; border-top: 1px solid var(--border); }
|
|
.article-references h2 { margin: 0 0 10px; font-size: 0.78rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-subtle); }
|
|
.article-references ol { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 5px; }
|
|
/* A source title is often a filename with underscores in it and no spaces to
|
|
break at — `2021_Fleisher_&_Ludwig's_Textbook_of_Pediatric_Emergency…` — so
|
|
the line has to be allowed to break anywhere or it runs off the screen. */
|
|
.article-references li {
|
|
font-size: 0.83rem; line-height: 1.5; color: var(--text-muted);
|
|
overflow-wrap: anywhere; word-break: break-word;
|
|
}
|
|
.article-ref-title { color: var(--text); font-weight: 600; }
|
|
.article-ref-pages { font-variant-numeric: tabular-nums; }
|
|
/* The checkable part of a paper. Set apart from the citation so the eye finds
|
|
it — plain text, because a reference list is what was read, not a set of
|
|
doors out of the article. */
|
|
.article-ref-pmid {
|
|
margin-left: 8px; font-size: .78rem; font-weight: 600;
|
|
color: var(--text-muted); white-space: nowrap;
|
|
}
|
|
|
|
@media (max-width: 900px) {
|
|
/* Four things in a bar this narrow is three too many; the rail and the
|
|
heading already say where you are. */
|
|
.asec-where { display: none; }
|
|
}
|
|
@media (max-width: 640px) {
|
|
.asec-controls { gap: 8px; }
|
|
.aview { padding: 6px 10px; font-size: 0.79rem; }
|
|
}
|
|
|
|
/* A view that is one section is shown as prose: no heading repeating the tab
|
|
above it, no chevron hiding the only thing there is to read. */
|
|
.asec-sole { padding-top: 4px; }
|
|
|
|
/* Coming from Editorial to write one. The queue is where that person was
|
|
working; this page is a library, and without a way back the only route is
|
|
the browser's own button. */
|
|
.articles-back {
|
|
display: inline-block; margin-bottom: 6px;
|
|
font-size: 0.82rem; font-weight: 600; color: var(--text-muted); text-decoration: none;
|
|
}
|
|
.articles-back:hover { color: var(--primary); }
|
|
|
|
.articles-form-actions { display: flex; align-items: center; gap: 8px; margin-top: 14px; }
|
|
/* A link, not a third button: leaving is not the same weight as the two
|
|
decisions about the form in front of it. */
|
|
.articles-leave {
|
|
margin-left: auto; font-size: 0.82rem; font-weight: 600;
|
|
color: var(--text-muted); text-decoration: none;
|
|
}
|
|
.articles-leave:hover { color: var(--primary); text-decoration: underline; }
|
|
|
|
@media (max-width: 560px) {
|
|
/* Three controls on one line becomes two lines rather than three squeezed
|
|
ones, and the way out stops being pushed off the right edge. */
|
|
.articles-form-actions { flex-wrap: wrap; }
|
|
.articles-leave { margin-left: 0; width: 100%; }
|
|
}
|
|
|
|
/* Leaving the editor. Save was the only control in the header, so the way out
|
|
of an editing sitting was the browser's back button — which throws the work
|
|
away and does not say so. */
|
|
.article-back {
|
|
display: inline-block; margin-bottom: 4px; padding: 0;
|
|
border: 0; background: none; cursor: pointer;
|
|
font: inherit; font-size: 0.82rem; font-weight: 600; color: var(--text-muted);
|
|
}
|
|
.article-back:hover { color: var(--primary); }
|
|
.article-discard-confirm {
|
|
display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap;
|
|
font-size: 0.82rem; color: var(--text-muted);
|
|
}
|
|
|
|
/* Deleting. At the foot of the editor and quiet until it is asked for: the
|
|
consequence differs by whether the article was ever published, so the
|
|
confirmation says which one this is rather than asking "are you sure". */
|
|
.article-danger { margin-top: 28px; padding-top: 16px; border-top: 1px solid var(--border); }
|
|
.article-danger p { margin: 0 0 10px; font-size: 0.86rem; line-height: 1.55; color: var(--text-muted); max-width: 62ch; }
|
|
.article-danger-actions { display: flex; gap: 8px; flex-wrap: wrap; }
|
|
.article-danger-open { color: var(--wrong-fg); }
|
|
|
|
/* The identifiers, at the top of the editor. Both are looked for and neither
|
|
was anywhere on the page: the id had to be read out of the address bar and
|
|
the slug out of the form field below.
|
|
|
|
The third chip is the useful one — the cross-reference marker itself, id and
|
|
title already assembled, because that is what somebody wants these two
|
|
numbers *for*. */
|
|
.article-ids { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
|
|
.article-id {
|
|
display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
|
|
padding: 4px 10px; border: 1px solid var(--border); border-radius: 999px;
|
|
background: var(--card-bg); font: inherit; font-size: 0.78rem; color: var(--text-muted);
|
|
}
|
|
.article-id:hover { border-color: var(--primary); color: var(--text); }
|
|
.article-id span { font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; font-size: 0.66rem; }
|
|
.article-id code {
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.76rem; color: var(--text);
|
|
}
|
|
.article-id.is-marker code { color: var(--primary); }
|
|
.article-id.is-marker { max-width: 100%; overflow: hidden; }
|
|
.article-id.is-marker code { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
.article-id.is-copied { border-color: var(--primary); background: color-mix(in srgb, var(--primary) 8%, transparent); }
|
|
.article-id-said { font-size: 0.76rem; font-weight: 600; color: var(--primary); }
|
|
|
|
@media (max-width: 560px) {
|
|
.article-id.is-marker { display: none; } /* The marker is a desktop errand. */
|
|
}
|
|
|
|
/* Cross-references that point at nothing, said on save — the last moment the
|
|
person who wrote the link is still looking at it. The backend has computed
|
|
this since markers existed; nothing had ever shown it. */
|
|
.article-broken {
|
|
display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px;
|
|
padding: 11px 14px; border-radius: 9px;
|
|
background: color-mix(in srgb, var(--wrong-fg) 7%, transparent);
|
|
border: 1px solid color-mix(in srgb, var(--wrong-fg) 24%, transparent);
|
|
font-size: 0.86rem;
|
|
}
|
|
.article-broken code {
|
|
display: inline-block; margin-right: 6px; padding: 1px 6px; border-radius: 5px;
|
|
background: var(--card-bg); font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
font-size: 0.78rem;
|
|
}
|
|
.article-broken-hint { font-size: 0.8rem; color: var(--text-muted); }
|
|
|
|
/* A job's progress, above the article it is working on. */
|
|
.article-ai-note {
|
|
display: flex; align-items: center; gap: 10px;
|
|
margin-bottom: 12px; padding: 10px 12px;
|
|
font-size: .86rem; color: var(--text);
|
|
background: var(--card-bg); border: 1px solid var(--border);
|
|
border-left: 3px solid var(--primary); border-radius: 8px;
|
|
}
|
|
.article-ai-note .spinner { width: 14px; height: 14px; border-width: 2px; flex: none; }
|
|
|
|
/* What a draft may draw on. Checkboxes with the reason beside them, because
|
|
"PubMed" alone does not tell an educator that the query leaves the building. */
|
|
.ai-draw-on { margin: 12px 0 4px; padding: 0; border: 0; }
|
|
.ai-draw-on legend {
|
|
padding: 0; font-size: .78rem; font-weight: 700; letter-spacing: .04em;
|
|
text-transform: uppercase; color: var(--text-muted);
|
|
}
|
|
.ai-draw-on label {
|
|
display: flex; align-items: flex-start; gap: 9px;
|
|
margin-top: 8px; cursor: pointer; font-size: .9rem;
|
|
}
|
|
.ai-draw-on input { margin-top: 3px; flex: none; }
|
|
.ai-draw-on span { display: flex; flex-direction: column; gap: 2px; }
|
|
.ai-draw-on small { font-size: .78rem; line-height: 1.5; color: var(--text-muted); }
|