dorfteich/apps/web/src/styles/base.css
Claude Fable 5 0003063c39
All checks were successful
CI / Auth e2e pack (push) Successful in 4m37s
CI / Import/export fidelity gate (push) Successful in 43s
CI / Lint, typecheck, test (push) Successful in 2m54s
CI / Build container images (push) Has been skipped
CD / Build and push images (push) Successful in 3m14s
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m8s
CD / Promote to Int (push) Successful in 9s
Add pageTool plugins with toc and page-index references (#77)
The read-only widget surface over page/pond data (ADR 0008 extension
point `pageTool`):

- Host: PageToolsPanel lists the pond's active pageTool surfaces behind
  disclosures — each sandbox iframe mounts lazily on first open and tears
  down on close. The same surfaces are insertable as plugin_block embeds
  (#76's insert picker now offers pageTool points too; the sandbox drives
  both through the same render lifecycle).
- New `ui.scrollToHeading(headingId)` capability: outline ids are derived
  from the doc and never stamped into the DOM, so the host resolves the id
  to its heading position via the shared extractOutline and scrolls the
  matching rendered heading.
- `readPond.listPages` now carries label *names* per summary
  (PagesService.pluginPageSummaries) — the page-index filter chips work on
  data the viewer could resolve anyway; per-page permission filtering
  stays in the service as before.
- Reference plugins packages/plugins/toc and packages/plugins/page-index:
  real SDK consumers (createPlugin + windowTransport), bundled with
  esbuild into the package ZIP; i18n de/en is inlined at build time — the
  sandbox CSP forbids runtime fetches, the i18n/ files stay the single
  source. The toc re-fetches its outline on a slow poll, so live heading
  edits appear once the collab server has re-derived the content cache.
- e2e page-tools.spec.ts covers the acceptance criteria: live outline
  updates after the persistence debounce, heading click scrolls, embedded
  page-index navigates via ui.openPage, and a label-restricted reader
  never sees the denied page in the index.
- CI: the auth-e2e job now runs the section-styles (missed in #75),
  plugin-blocks, and page-tools packs, with login-rate-limit resets.
- plugins.e2e.db.test clears the plugin registry up front: a local dev DB
  is shared with the e2e stack, whose installed real `toc` would otherwise
  collide with the fixture of the same id.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
2026-07-11 13:27:30 +02:00

2168 lines
39 KiB
CSS

*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body,
#root {
height: 100%;
margin: 0;
}
body {
font-family: var(--font-body);
font-weight: var(--font-weight-body);
color: var(--color-text);
background: var(--color-bg);
line-height: 1.6;
}
h1,
h2,
h3,
h4 {
font-family: var(--font-heading);
font-weight: var(--font-weight-heading);
line-height: 1.25;
}
code,
pre {
font-family: var(--font-mono);
font-weight: var(--font-weight-mono);
}
/* A pond's content root (ADR 0016): sets --font-* (via PondFontScope) so its
* body text uses the pond's body font; headings and code re-resolve the same
* variables through the global rules above. */
.pond-font-scope {
font-family: var(--font-body);
font-weight: var(--font-weight-body);
}
a {
color: var(--color-accent);
}
button {
font: inherit;
}
/* Layout skeleton */
.app {
display: grid;
grid-template-rows: var(--topbar-height) 1fr;
height: 100%;
}
.app-body {
display: flex;
min-height: 0;
}
.topbar {
display: flex;
align-items: center;
gap: var(--space-4);
padding: 0 var(--space-4);
border-bottom: 1px solid var(--color-border);
background: var(--color-bg);
}
.topbar__brand {
font-family: var(--font-heading);
font-size: 1.1rem;
color: var(--color-text);
text-decoration: none;
}
.topbar__spacer {
flex: 1;
}
.sidebar {
width: var(--sidebar-width);
flex-shrink: 0;
border-right: 1px solid var(--color-border);
background: var(--color-bg-subtle);
padding: var(--space-4);
overflow-y: auto;
transition:
margin-left 0.18s ease-out,
opacity 0.15s ease-out;
}
.sidebar--collapsed {
margin-left: calc(-1 * var(--sidebar-width));
opacity: 0;
}
.sidebar__hint {
color: var(--color-text-muted);
font-size: 0.9rem;
}
.sidebar__header {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-2);
margin-bottom: var(--space-3);
}
.sidebar__pond-name {
font-size: 1rem;
margin: 0;
}
.sidebar__sort {
font: inherit;
font-size: 0.85rem;
border: 1px solid var(--color-border);
border-radius: var(--radius);
background: var(--color-bg);
padding: var(--space-1) var(--space-2);
}
.sidebar__trash-link {
font-size: 0.85rem;
white-space: nowrap;
}
.sidebar__pages {
list-style: none;
margin: 0 0 var(--space-3);
padding: 0;
}
.sidebar__page {
display: block;
padding: var(--space-1) var(--space-2);
border-radius: var(--radius);
color: var(--color-text);
text-decoration: none;
font-size: 0.95rem;
}
.sidebar__page:hover {
background: var(--color-bg);
}
.sidebar__page--active {
background: var(--color-bg);
font-weight: 600;
}
.sidebar__new-page {
font-size: 0.9rem;
}
.sidebar__new-page-form {
margin-top: var(--space-2);
}
.sidebar__new-page-form .field {
margin-bottom: var(--space-2);
}
.sidebar__new-page-actions {
display: flex;
align-items: center;
gap: var(--space-3);
}
.sidebar__import {
margin-top: var(--space-2);
}
.sidebar__import-action {
font-size: 0.9rem;
}
.sidebar__import-list {
list-style: none;
margin: var(--space-2) 0 0;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--space-2);
}
.sidebar__import-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: var(--space-2);
font-size: 0.85rem;
}
.sidebar__import-name {
flex: 1 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.sidebar__import-status {
color: var(--color-text-muted);
}
.sidebar__import-item--failed .sidebar__import-status {
color: var(--color-danger);
}
.sidebar__import-actions {
display: flex;
gap: var(--space-2);
}
.pond-home {
max-width: 36rem;
}
.main {
flex: 1;
min-width: 0;
overflow-y: auto;
padding: var(--space-6) var(--space-8);
}
.icon-button {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
border: 1px solid transparent;
border-radius: var(--radius);
background: transparent;
cursor: pointer;
color: var(--color-text);
}
.icon-button:hover {
background: var(--color-bg-subtle);
border-color: var(--color-border);
}
.icon-button:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 1px;
}
.status-pill {
display: inline-flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-1) var(--space-3);
border-radius: 999px;
border: 1px solid var(--color-border);
font-size: 0.9rem;
}
.status-pill--ok {
color: var(--color-ok);
}
.status-pill--error {
color: var(--color-danger);
}
/* Forms */
.field {
display: block;
margin-bottom: var(--space-4);
}
.field__label {
display: block;
margin-bottom: var(--space-1);
font-size: 0.9rem;
color: var(--color-text-muted);
}
.field input,
.field select {
width: 100%;
padding: var(--space-2) var(--space-3);
border: 1px solid var(--color-border);
border-radius: var(--radius);
font: inherit;
background: var(--color-bg);
}
.field input:focus-visible,
.field select:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 1px;
}
.field__hint,
.field__error {
display: block;
margin-top: var(--space-1);
font-size: 0.85rem;
}
.field__hint {
color: var(--color-text-muted);
}
.field__error {
color: var(--color-danger);
}
.button {
display: inline-block;
padding: var(--space-2) var(--space-4);
border: none;
border-radius: var(--radius);
background: var(--color-accent);
color: var(--color-accent-contrast);
cursor: pointer;
text-decoration: none;
font: inherit;
}
.button:disabled {
opacity: 0.6;
cursor: default;
}
.linklike {
background: none;
border: none;
padding: 0;
color: var(--color-accent);
text-decoration: underline;
cursor: pointer;
font: inherit;
}
.form-banner {
padding: var(--space-2) var(--space-3);
border: 1px solid var(--color-border);
border-radius: var(--radius);
margin-bottom: var(--space-4);
font-size: 0.95rem;
}
.form-banner--error {
border-color: var(--color-danger);
color: var(--color-danger);
}
.form-banner--ok {
border-color: var(--color-ok);
color: var(--color-ok);
}
/* Auth pages */
.auth-card {
max-width: 24rem;
margin: var(--space-8) auto;
}
.auth-card__links {
margin-top: var(--space-4);
font-size: 0.95rem;
}
/* Settings */
.settings-section {
max-width: 36rem;
margin-bottom: var(--space-8);
padding-bottom: var(--space-6);
border-bottom: 1px solid var(--color-border);
}
.table {
width: 100%;
border-collapse: collapse;
margin-bottom: var(--space-4);
}
.table th,
.table td {
text-align: left;
padding: var(--space-2) var(--space-3);
border-bottom: 1px solid var(--color-border);
font-size: 0.95rem;
}
.table th {
color: var(--color-text-muted);
font-weight: 400;
}
.badge {
display: inline-block;
margin-left: var(--space-2);
padding: 0 var(--space-2);
border-radius: 999px;
background: var(--color-bg-subtle);
border: 1px solid var(--color-border);
font-size: 0.8rem;
color: var(--color-text-muted);
}
/* User menu */
.user-menu {
position: relative;
}
.user-menu__trigger {
background: none;
border: 1px solid transparent;
border-radius: var(--radius);
padding: var(--space-1) var(--space-3);
cursor: pointer;
}
.user-menu__trigger:hover {
border-color: var(--color-border);
}
.user-menu__list {
position: absolute;
right: 0;
top: calc(100% + 4px);
min-width: 12rem;
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius);
box-shadow: 0 4px 12px rgb(0 0 0 / 0.08);
display: flex;
flex-direction: column;
z-index: 10;
}
.user-menu__list a,
.user-menu__list button {
padding: var(--space-2) var(--space-3);
text-align: left;
background: none;
border: none;
color: var(--color-text);
text-decoration: none;
cursor: pointer;
font: inherit;
}
.user-menu__list a:hover,
.user-menu__list button:hover {
background: var(--color-bg-subtle);
}
.topbar__nav {
display: flex;
gap: var(--space-4);
}
/* Page editor (issue #25) */
.editor-page {
max-width: 48rem;
margin: 0 auto;
}
.editor-page__header {
display: flex;
align-items: center;
gap: var(--space-4);
margin-bottom: var(--space-4);
}
.editor-page__title {
flex: 1;
border: none;
background: none;
font-family: var(--font-heading);
font-weight: var(--font-weight-heading);
font-size: 1.6rem;
padding: var(--space-1) 0;
}
.editor-page__title:disabled {
color: var(--color-text);
opacity: 1;
}
.editor-page__title:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 2px;
}
.editor-page__actions {
display: flex;
gap: var(--space-2);
}
/* The export buttons flow inline with the other page actions (same gap). */
.editor-page__export {
display: contents;
}
.pond-export__hint {
color: var(--color-text-muted);
margin-bottom: var(--space-2);
}
/* Pond appearance (fonts) settings — issue #66 */
.appearance__intro {
color: var(--color-text-muted);
}
.appearance__slot {
display: flex;
flex-wrap: wrap;
align-items: end;
gap: var(--space-3);
padding: var(--space-3) 0;
border-top: 1px solid var(--color-border);
}
.appearance__slot-label {
flex-basis: 100%;
font-weight: 600;
}
.appearance__field {
display: flex;
flex-direction: column;
gap: var(--space-1);
}
.appearance__preview {
flex: 1 1 16rem;
margin: 0;
font-size: 1.1rem;
}
.appearance__actions {
display: flex;
align-items: center;
gap: var(--space-4);
margin-top: var(--space-3);
}
.font-catalog__table {
border-collapse: collapse;
width: 100%;
}
.font-catalog__table th,
.font-catalog__table td {
text-align: left;
padding: var(--space-2) var(--space-3);
border-bottom: 1px solid var(--color-border);
}
.editor-shell {
border: 1px solid var(--color-border);
border-radius: var(--radius);
}
.editor-toolbar {
display: flex;
flex-wrap: wrap;
gap: var(--space-3);
padding: var(--space-2) var(--space-3);
border-bottom: 1px solid var(--color-border);
background: var(--color-bg-subtle);
}
.editor-toolbar__group {
display: flex;
gap: var(--space-1);
padding-right: var(--space-3);
border-right: 1px solid var(--color-border);
}
.editor-toolbar__group:last-child {
border-right: none;
padding-right: 0;
}
.editor-toolbar__section-select {
height: 1.75rem;
max-width: 12rem;
padding: 0 var(--space-1);
border: 1px solid var(--color-border);
border-radius: var(--radius);
background: var(--color-bg);
color: var(--color-text);
font-size: 0.85rem;
}
/* A section whose plugin is disabled/removed is an invisible wrapper (its
* dt-style-… class matches no stylesheet). While writing, a faint dashed
* hint keeps every section findable, so "unwrap" has a visible target. */
.editor-content .dt-section {
border-radius: var(--radius);
outline: 1px dashed transparent;
outline-offset: 2px;
}
.editor-content:focus-within .dt-section {
outline-color: var(--color-border);
}
/* The page-tools panel (issue #77): active pageTool plugin surfaces behind
* disclosures; each iframe mounts lazily on first open. */
.page-tools {
margin: var(--space-2) var(--space-3);
border: 1px solid var(--color-border);
border-radius: var(--radius);
}
.page-tools__tool + .page-tools__tool {
border-top: 1px solid var(--color-border);
}
.page-tools__toggle {
display: block;
width: 100%;
padding: var(--space-2) var(--space-3);
border: none;
background: var(--color-bg-subtle);
color: var(--color-text);
text-align: left;
font-size: 0.9rem;
cursor: pointer;
}
.page-tools__tool .plugin-frame-host {
padding: var(--space-2) var(--space-3);
}
/* A plugin-owned block (issue #76): a framed island in the content column.
* The sandbox iframe sizes itself via ui.resize; the bar carries the plugin
* name and the edit affordance. */
.plugin-block {
margin: 0.75rem 0;
border: 1px solid var(--color-border);
border-radius: var(--radius);
background: var(--color-bg);
}
.plugin-block--selected {
outline: 2px solid var(--color-accent);
outline-offset: 1px;
}
.plugin-block__bar {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-2);
padding: var(--space-1) var(--space-2);
border-bottom: 1px solid var(--color-border);
background: var(--color-bg-subtle);
font-size: 0.8rem;
color: var(--color-text-muted);
}
.plugin-block__mount .plugin-frame {
display: block;
width: 100%;
border: none;
}
.plugin-block__fallback {
padding: var(--space-2) var(--space-3);
}
.plugin-block__fallback-text {
margin: 0;
}
.plugin-block__fallback-note {
margin: var(--space-1) 0 0;
font-size: 0.8rem;
color: var(--color-text-muted);
}
.toolbar-button {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 1.75rem;
height: 1.75rem;
padding: 0 var(--space-1);
border: 1px solid transparent;
border-radius: var(--radius);
background: transparent;
cursor: pointer;
color: var(--color-text);
font-size: 0.9rem;
}
.toolbar-button:hover:not(:disabled) {
background: var(--color-bg);
border-color: var(--color-border);
}
.toolbar-button:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 1px;
}
.toolbar-button--active {
background: var(--color-accent);
color: var(--color-accent-contrast);
}
.toolbar-button:disabled {
opacity: 0.4;
cursor: default;
}
.editor-link-form {
display: flex;
gap: var(--space-1);
align-items: center;
}
.editor-link-form input {
padding: var(--space-1) var(--space-2);
border: 1px solid var(--color-border);
border-radius: var(--radius);
font: inherit;
font-size: 0.9rem;
}
.editor-link-form__error {
flex-basis: 100%;
font-size: 0.8rem;
color: var(--color-danger);
}
.editor-link-menu {
padding: var(--space-2);
border: 1px solid var(--color-border);
border-radius: var(--radius);
background: var(--color-bg);
box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
}
.editor-link-menu__actions {
display: flex;
gap: var(--space-1);
}
.editor-connection {
padding: var(--space-1) var(--space-3);
font-size: 0.85rem;
color: var(--color-text-muted);
}
.editor-connection[data-status='connected'] {
color: var(--color-accent);
}
.editor-connection[data-status='offline'] {
color: var(--color-danger);
}
.presence-strip {
display: flex;
gap: calc(-1 * var(--space-1));
align-items: center;
padding: var(--space-1) var(--space-3);
}
.presence-avatar {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: 1.75rem;
height: 1.75rem;
margin-left: -0.4rem;
border: 2px solid var(--color-bg);
border-radius: 50%;
color: #ffffff;
font-size: 0.7rem;
font-weight: 600;
}
.presence-avatar:first-child {
margin-left: 0;
}
.presence-avatar--overflow {
background: var(--color-text-muted);
}
.presence-avatar__ro {
position: absolute;
right: -0.15rem;
bottom: -0.15rem;
font-size: 0.75rem;
line-height: 1;
}
/* Remote collaboration carets and selections (issue #37). */
.collab-caret {
position: relative;
margin-left: -1px;
margin-right: -1px;
border-left: 1px solid;
border-right: 1px solid;
word-break: normal;
pointer-events: none;
}
.collab-caret--hidden {
display: none;
}
.collab-caret__label {
position: absolute;
top: -1.4em;
left: -1px;
padding: 0.05rem 0.3rem;
border-radius: 3px 3px 3px 0;
color: #ffffff;
font-size: 0.7rem;
font-weight: 600;
white-space: nowrap;
user-select: none;
}
.collab-selection {
border-radius: 2px;
}
.editor-banner {
margin: var(--space-1) var(--space-3);
padding: var(--space-2) var(--space-3);
border-radius: var(--radius-sm, 4px);
font-size: 0.9rem;
}
.editor-banner--info {
background: var(--color-bg-subtle);
border: 1px solid var(--color-border);
color: var(--color-text-muted);
}
.editor-banner--error {
background: var(--color-bg-subtle);
border: 1px solid var(--color-danger);
color: var(--color-danger);
}
.editor-page__body {
display: flex;
gap: var(--space-4);
align-items: flex-start;
}
.editor-page__body > .editor-shell {
flex: 1 1 auto;
min-width: 0;
}
.history-panel {
flex: 0 0 22rem;
max-width: 22rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm, 4px);
padding: var(--space-3);
max-height: 80vh;
overflow-y: auto;
}
.history-panel__header {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--space-2);
}
.history-panel__header h2 {
font-size: 1rem;
margin: 0;
}
.history-panel__list {
list-style: none;
margin: var(--space-2) 0;
padding: 0;
}
.history-panel__item {
display: flex;
flex-direction: column;
width: 100%;
text-align: left;
gap: 2px;
padding: var(--space-2);
border: 1px solid transparent;
border-radius: var(--radius-sm, 4px);
background: none;
cursor: pointer;
color: inherit;
}
.history-panel__item:hover {
background: var(--color-bg-subtle);
}
.history-panel__item[aria-current='true'] {
border-color: var(--color-border);
background: var(--color-bg-subtle);
}
.history-panel__when {
font-weight: 600;
font-size: 0.9rem;
}
.history-panel__meta {
font-size: 0.8rem;
color: var(--color-text-muted);
}
.history-panel__error {
color: var(--color-danger);
}
.history-panel__diff {
white-space: pre-wrap;
word-break: break-word;
font-size: 0.85rem;
background: var(--color-bg-subtle);
padding: var(--space-2);
border-radius: var(--radius-sm, 4px);
}
.diff--added {
background: color-mix(in srgb, green 22%, transparent);
text-decoration: none;
}
.diff--removed {
background: color-mix(in srgb, red 22%, transparent);
text-decoration: line-through;
}
.history-panel__preview {
border-top: 1px solid var(--color-border);
padding-top: var(--space-2);
}
.access-revoked__title {
font-weight: 600;
margin: 0 0 var(--space-1);
}
.access-revoked__description {
margin: 0 0 var(--space-2);
}
.access-revoked__actions {
display: flex;
flex-wrap: wrap;
gap: var(--space-2);
}
.editor-content {
padding: var(--space-4) var(--space-6);
min-height: 12rem;
}
.editor-content .ProseMirror {
outline: none;
}
.editor-content h1,
.editor-content h2,
.editor-content h3,
.editor-content h4 {
margin-top: var(--space-6);
margin-bottom: var(--space-2);
}
.editor-content blockquote {
margin: var(--space-4) 0;
padding-left: var(--space-4);
border-left: 3px solid var(--color-border);
color: var(--color-text-muted);
}
.editor-content pre {
padding: var(--space-3);
border-radius: var(--radius);
background: var(--color-bg-subtle);
overflow-x: auto;
}
.editor-content code {
background: var(--color-bg-subtle);
border-radius: 3px;
padding: 0 0.25em;
}
.editor-content pre code {
background: none;
padding: 0;
}
.editor-content ul[data-type='task_list'] {
list-style: none;
padding-left: var(--space-2);
}
.editor-content ul[data-type='task_list'] li {
display: flex;
align-items: flex-start;
gap: var(--space-2);
}
.editor-content table {
border-collapse: collapse;
margin: var(--space-4) 0;
width: 100%;
}
.editor-content table td,
.editor-content table th {
border: 1px solid var(--color-border);
padding: var(--space-2) var(--space-3);
}
.editor-content table th {
background: var(--color-bg-subtle);
text-align: left;
}
.editor-content hr {
border: none;
border-top: 1px solid var(--color-border);
margin: var(--space-6) 0;
}
.editor-image {
position: relative;
display: inline-block;
max-width: 100%;
vertical-align: bottom;
}
.editor-image img {
max-width: 100%;
border-radius: var(--radius);
}
.editor-image__controls {
display: flex;
flex-direction: column;
gap: var(--space-2);
position: absolute;
top: 100%;
left: 0;
z-index: 1;
margin-top: var(--space-1);
padding: var(--space-2) var(--space-3);
border: 1px solid var(--color-border);
border-radius: var(--radius);
background: var(--color-bg);
box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
white-space: nowrap;
}
.editor-image__alt {
display: flex;
flex-direction: column;
gap: var(--space-1);
font-size: 0.85rem;
color: var(--color-text-muted);
}
.editor-image__alt input {
padding: var(--space-1) var(--space-2);
border: 1px solid var(--color-border);
border-radius: var(--radius);
font: inherit;
font-size: 0.9rem;
}
.editor-image__widths {
display: flex;
gap: var(--space-1);
}
.editor-image-upload {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 3rem;
min-height: 2rem;
padding: var(--space-1) var(--space-2);
border: 1px dashed var(--color-border);
border-radius: var(--radius);
background: var(--color-bg-subtle);
color: var(--color-text-muted);
font-size: 0.85rem;
}
.editor-image-upload--error {
border-color: var(--color-danger);
color: var(--color-danger);
}
/* Pond trash (issue #31) */
.trash-page {
max-width: 48rem;
margin: 0 auto;
}
.trash-page__list {
list-style: none;
margin: var(--space-4) 0 0;
padding: 0;
}
.trash-page__item {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-2) 0;
border-bottom: 1px solid var(--color-border);
}
.trash-page__title {
flex: 1;
font-weight: var(--font-weight-heading);
}
.trash-page__deleted-at {
color: var(--color-text-muted);
font-size: 0.85rem;
}
/* Labels (issue #44) --------------------------------------------------- */
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* Colored chips on sidebar page entries. */
.label-chips {
display: flex;
flex-wrap: wrap;
gap: var(--space-1);
margin: var(--space-1) 0 0 var(--space-2);
}
.label-chip {
display: inline-block;
padding: 0 var(--space-2);
border-radius: 999px;
font-size: 0.72rem;
line-height: 1.5;
white-space: nowrap;
}
.label-chip__swatch {
display: inline-block;
width: 0.75rem;
height: 0.75rem;
border-radius: 50%;
border: 1px solid var(--color-border);
flex: 0 0 auto;
}
/* Sidebar label filter. */
.sidebar__filter {
margin-bottom: var(--space-3);
font-size: 0.9rem;
}
.sidebar__filter > summary {
cursor: pointer;
color: var(--color-text-muted);
padding: var(--space-1) 0;
}
.sidebar__filter-list {
list-style: none;
margin: var(--space-1) 0;
padding: 0;
max-height: 14rem;
overflow-y: auto;
}
.sidebar__filter-option {
display: flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-1) 0;
cursor: pointer;
}
.sidebar__settings-link {
font-size: 0.85rem;
}
/* Pond settings page + label manager. */
.pond-settings-page {
max-width: 48rem;
}
/* Member management (issue #54) */
.member-manager__intro,
.member-manager__note,
.member-manager__empty {
color: var(--color-text-muted);
margin-bottom: var(--space-3);
}
.member-seats {
list-style: none;
display: flex;
flex-wrap: wrap;
gap: var(--space-2);
margin: 0 0 var(--space-3);
padding: 0;
}
.member-seats__item {
background: var(--color-surface-muted, rgba(127, 127, 127, 0.12));
border-radius: var(--radius-sm, 0.375rem);
padding: var(--space-1) var(--space-2);
font-size: 0.875rem;
}
.member-add {
display: flex;
flex-wrap: wrap;
align-items: flex-end;
gap: var(--space-2);
margin-bottom: var(--space-3);
}
.member-add__field {
display: flex;
flex-direction: column;
gap: var(--space-1);
font-size: 0.875rem;
}
.member-add__quota-full {
flex-basis: 100%;
color: var(--color-danger);
margin: 0;
font-size: 0.875rem;
}
.member-search {
width: 100%;
margin-bottom: var(--space-3);
}
.member-group {
margin-bottom: var(--space-4);
}
.member-group__title {
font-size: 0.875rem;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--color-text-muted);
margin: 0 0 var(--space-2);
}
.member-group__list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--space-1);
}
.member-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-2);
padding: var(--space-2);
border: 1px solid var(--color-border, rgba(127, 127, 127, 0.25));
border-radius: var(--radius-sm, 0.375rem);
}
.member-row__username,
.member-row__owner-badge {
color: var(--color-text-muted);
}
.member-row__actions {
display: flex;
align-items: center;
gap: var(--space-2);
}
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.label-manager__description {
color: var(--color-text-muted);
margin-bottom: var(--space-3);
}
.label-manager__new-root {
display: flex;
gap: var(--space-2);
margin-bottom: var(--space-3);
}
.label-manager__error {
color: var(--color-danger);
margin-bottom: var(--space-3);
}
.label-manager__empty {
color: var(--color-text-muted);
}
.label-tree {
list-style: none;
margin: 0;
padding: 0;
}
.label-tree .label-tree {
margin-left: var(--space-4);
border-left: 1px solid var(--color-border);
padding-left: var(--space-3);
}
.label-node {
display: flex;
align-items: center;
gap: var(--space-2);
flex-wrap: wrap;
padding: var(--space-1) 0;
}
.label-node__swatch {
display: inline-block;
width: 0.9rem;
height: 0.9rem;
border-radius: 50%;
border: 1px solid var(--color-border);
flex: 0 0 auto;
}
.label-node__name {
font-weight: 600;
}
.label-node__actions {
display: flex;
align-items: center;
gap: var(--space-2);
margin-left: auto;
}
.label-node__color {
width: 1.75rem;
height: 1.5rem;
padding: 0;
border: 1px solid var(--color-border);
border-radius: var(--radius);
background: none;
cursor: pointer;
}
.label-node__delete {
color: var(--color-danger);
}
.label-tree__child-form {
display: flex;
gap: var(--space-2);
margin: var(--space-1) 0 var(--space-2) var(--space-4);
}
/* Page label picker panel. */
.label-picker {
flex: 0 0 20rem;
max-width: 20rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm, 4px);
padding: var(--space-3);
max-height: 80vh;
overflow-y: auto;
}
.label-picker__header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: var(--space-2);
}
.label-picker__search {
width: 100%;
margin-bottom: var(--space-2);
}
.label-picker__list {
list-style: none;
margin: 0;
padding: 0;
}
.label-picker__option {
display: flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-1) 0;
cursor: pointer;
}
.label-picker__empty {
color: var(--color-text-muted);
}
/* Manual page reordering (issue #45) ----------------------------------- */
.sidebar__page-item {
display: flex;
align-items: center;
gap: var(--space-1);
}
.sidebar__page-item .sidebar__page {
flex: 1 1 auto;
min-width: 0;
}
.sidebar__page-item--draggable {
cursor: grab;
}
.sidebar__reorder {
display: inline-flex;
gap: 2px;
flex: 0 0 auto;
}
.sidebar__reorder-btn {
border: 1px solid var(--color-border);
background: var(--color-bg);
border-radius: var(--radius);
color: var(--color-text-muted);
width: 1.4rem;
height: 1.4rem;
line-height: 1;
cursor: pointer;
padding: 0;
}
.sidebar__reorder-btn:disabled {
opacity: 0.35;
cursor: default;
}
.sidebar__reorder-btn:not(:disabled):hover {
background: var(--color-bg-subtle);
color: var(--color-text);
}
/* Wikilinks (issue #46) ------------------------------------------------- */
.wikilink-nodeview {
display: inline;
}
.wikilink {
color: var(--color-accent);
text-decoration: none;
border-bottom: 1px solid transparent;
cursor: pointer;
}
.wikilink:hover {
border-bottom-color: currentColor;
}
/* A link to a page that does not exist yet. */
.wikilink--phantom {
color: var(--color-text-muted);
border-bottom: 1px dashed currentColor;
}
.wikilink-suggest {
list-style: none;
margin: 0;
padding: var(--space-1);
min-width: 14rem;
max-width: 22rem;
max-height: 16rem;
overflow-y: auto;
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius);
box-shadow: 0 4px 16px rgb(0 0 0 / 12%);
z-index: 30;
}
.wikilink-suggest__item {
display: block;
width: 100%;
text-align: left;
padding: var(--space-1) var(--space-2);
border: 0;
border-radius: var(--radius);
background: none;
color: var(--color-text);
cursor: pointer;
font-size: 0.95rem;
}
.wikilink-suggest__item.is-active,
.wikilink-suggest__item:hover {
background: var(--color-bg-subtle);
}
/* Backlinks + missing pages (issue #48) --------------------------------- */
.backlinks {
margin-top: var(--space-6);
border-top: 1px solid var(--color-border);
padding-top: var(--space-3);
}
.backlinks > summary {
cursor: pointer;
font-weight: 600;
color: var(--color-text-muted);
}
.backlinks__list {
list-style: none;
margin: var(--space-2) 0 0;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--space-2);
}
.backlinks__link {
font-weight: 600;
}
.backlinks__snippet {
margin: 2px 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
}
.phantom-pages__description {
color: var(--color-text-muted);
margin-bottom: var(--space-3);
}
.phantom-pages__empty {
color: var(--color-text-muted);
}
.phantom-pages__list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--space-3);
}
.phantom-pages__head {
display: flex;
align-items: center;
gap: var(--space-3);
}
.phantom-pages__slug {
font-family: var(--font-mono);
background: var(--color-bg-subtle);
padding: 2px var(--space-2);
border-radius: var(--radius);
}
.phantom-pages__referrers {
margin: var(--space-1) 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
}
/* Search palette (issue #50) -------------------------------------------- */
.topbar__search {
display: inline-flex;
align-items: center;
gap: var(--space-1);
border: 1px solid var(--color-border);
background: var(--color-bg-subtle);
border-radius: var(--radius);
padding: var(--space-1) var(--space-3);
color: var(--color-text-muted);
cursor: pointer;
font-size: 0.9rem;
}
.topbar__search:hover {
background: var(--color-bg);
color: var(--color-text);
}
.search-overlay {
position: fixed;
inset: 0;
z-index: 100;
display: flex;
justify-content: center;
align-items: flex-start;
padding-top: 10vh;
}
.search-backdrop {
position: absolute;
inset: 0;
background: rgb(0 0 0 / 35%);
}
.search-palette {
position: relative;
width: min(40rem, 92vw);
max-height: 75vh;
overflow-y: auto;
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius);
box-shadow: 0 12px 40px rgb(0 0 0 / 25%);
padding: var(--space-3);
}
.search-palette__input {
width: 100%;
font-size: 1.1rem;
padding: var(--space-2);
}
.search-palette__scope {
display: flex;
align-items: center;
gap: var(--space-4);
margin: var(--space-2) 0;
font-size: 0.9rem;
color: var(--color-text-muted);
}
.search-palette__labels ul {
list-style: none;
margin: var(--space-1) 0 0;
padding: 0;
max-height: 10rem;
overflow-y: auto;
}
.search-palette__labels label {
display: flex;
align-items: center;
gap: var(--space-2);
padding: 2px 0;
}
.search-palette__hint {
color: var(--color-text-muted);
padding: var(--space-3);
text-align: center;
}
.search-palette__recent ul {
list-style: none;
margin: 0;
padding: 0;
}
.search-palette__recent li {
padding: var(--space-1) var(--space-2);
}
.search-results {
list-style: none;
margin: 0;
padding: 0;
}
.search-result {
display: block;
width: 100%;
text-align: left;
border: 0;
background: none;
border-radius: var(--radius);
padding: var(--space-2);
cursor: pointer;
color: var(--color-text);
}
.search-result--active,
.search-result:hover {
background: var(--color-bg-subtle);
}
.search-result__title {
font-weight: 600;
margin-right: var(--space-2);
}
.search-result__pond {
color: var(--color-text-muted);
font-size: 0.85rem;
}
.search-result__snippet {
display: block;
margin-top: 2px;
color: var(--color-text-muted);
font-size: 0.9rem;
}
.search-result__snippet mark {
background: var(--color-accent);
color: var(--color-accent-contrast);
border-radius: 2px;
padding: 0 2px;
}
/* Access rules (issue #55) */
.access-rules__intro,
.access-rules__empty {
color: var(--color-text-muted);
margin-bottom: var(--space-3);
}
.rule-add {
border: 1px solid var(--color-border, rgba(127, 127, 127, 0.25));
border-radius: var(--radius-sm, 0.375rem);
padding: var(--space-3);
margin-bottom: var(--space-4);
}
.rule-add__title {
margin: 0 0 var(--space-2);
font-size: 0.875rem;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--color-text-muted);
}
.rule-add__row {
display: flex;
flex-wrap: wrap;
gap: var(--space-2);
margin-bottom: var(--space-2);
}
.rule-add__field {
display: flex;
flex-direction: column;
gap: var(--space-1);
font-size: 0.875rem;
}
.rule-add__public-warning {
display: flex;
align-items: center;
gap: var(--space-2);
}
.rule-groups,
.rule-group__list {
list-style: none;
margin: 0;
padding: 0;
}
.rule-group {
margin-bottom: var(--space-3);
}
.rule-group__subject {
margin: 0 0 var(--space-1);
font-size: 0.9375rem;
}
.rule-item {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-2);
padding: var(--space-1) 0;
}
/* Public read-only page view (issue #56) */
.public-page {
max-width: 48rem;
margin: 0 auto;
}
.public-page__badge {
display: inline-block;
padding: var(--space-1) var(--space-2);
border-radius: 999px;
background: var(--color-bg-subtle);
border: 1px solid var(--color-border);
font-size: 0.8rem;
color: var(--color-text-muted);
margin-bottom: var(--space-3);
}
.public-page__pond {
color: var(--color-text-muted);
font-size: 0.9rem;
margin: 0;
}
.public-page__body img {
max-width: 100%;
height: auto;
}
/* Effective-permissions inspector (issue #57) */
.inspector__intro {
color: var(--color-text-muted);
margin-bottom: var(--space-3);
}
.inspector__controls {
display: flex;
flex-wrap: wrap;
gap: var(--space-3);
margin-bottom: var(--space-3);
}
.inspector__field {
display: flex;
flex-direction: column;
gap: var(--space-1);
font-size: 0.875rem;
}
.inspector__result {
margin: 0;
}
.inspector__outcome {
display: flex;
gap: var(--space-2);
padding: var(--space-2);
border-left: 3px solid var(--color-border);
margin-bottom: var(--space-2);
}
.inspector__outcome dt {
min-width: 5rem;
font-weight: 600;
}
.inspector__outcome dd {
margin: 0;
}
.inspector__outcome--allow {
border-left-color: var(--color-ok);
}
.inspector__outcome--deny {
border-left-color: var(--color-danger);
}
.inspector__reason {
color: var(--color-text-muted);
}
/* Quota override manager (issue #58) */
.quota-manager__lookup {
display: flex;
flex-wrap: wrap;
gap: var(--space-2);
margin-bottom: var(--space-3);
}
.quota-manager__subject {
font-weight: 600;
margin-bottom: var(--space-2);
}
.quota-row__override {
display: flex;
align-items: center;
gap: var(--space-2);
}
.quota-row__input {
width: 8rem;
}
.quota-row--over .quota-row__usage {
color: var(--color-danger);
}
.quota-row__flag {
color: var(--color-danger);
}
/* User management (issue #59) */
.user-manager__search {
width: 100%;
margin-bottom: var(--space-3);
}
.user-row__username,
.user-row__email {
color: var(--color-text-muted);
font-size: 0.85rem;
}
.user-row__actions {
display: flex;
flex-wrap: wrap;
gap: var(--space-2);
}
.user-row__delete-confirm {
color: var(--color-danger);
font-weight: 600;
}
.user-manager__pager {
display: flex;
align-items: center;
gap: var(--space-3);
margin-top: var(--space-3);
}
/* Attachments: page section + pond file manager (issue #61) */
.editor-shell__tools {
display: flex;
justify-content: flex-end;
gap: var(--space-2);
margin-bottom: var(--space-2);
}
.attachments-panel {
border: 1px solid var(--color-border);
border-radius: var(--radius-sm, 0.375rem);
padding: var(--space-3);
margin-bottom: var(--space-3);
background: var(--color-surface-muted, rgba(127, 127, 127, 0.06));
}
.attachments-panel__header {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-2);
margin-bottom: var(--space-2);
}
.attachments-panel__header h3 {
margin: 0;
}
.attachments-panel__upload {
display: flex;
align-items: center;
gap: var(--space-2);
margin-bottom: var(--space-3);
}
.attachments-panel__input {
display: none;
}
.attachments-panel__empty,
.pond-file-manager__empty {
color: var(--color-text-muted);
}
.attachments-panel__list,
.pond-file-manager__list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--space-1);
}
.attachments-item {
display: flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-1) 0;
flex-wrap: wrap;
}
.attachments-item__glyph {
font-size: 1.1rem;
}
.attachments-item__name {
font-weight: 600;
}
.attachments-item__meta {
color: var(--color-text-muted);
font-size: 0.875rem;
}
.attachments-item__orphan {
color: var(--color-danger, #b91c1c);
font-style: italic;
}
.attachments-item__actions {
margin-left: auto;
display: flex;
gap: var(--space-2);
}
.pond-file-manager__usage {
color: var(--color-text-muted);
margin-bottom: var(--space-2);
}
/* --- Plugin sandbox frames (issue #73) ------------------------------------ */
.plugin-frame-host__mount .plugin-frame {
display: block;
width: 100%;
height: 120px;
border: none;
background: transparent;
}
.plugin-frame-host[data-state='failed'] .plugin-frame-host__mount {
display: none;
}
.plugin-frame-host__status {
color: var(--color-text-muted);
font-size: 0.875rem;
}
.plugin-frame-host__status--failed {
color: var(--color-danger, #b91c1c);
border: 1px dashed var(--color-danger, #b91c1c);
border-radius: 4px;
padding: var(--space-2);
}
.plugin-preview__version {
color: var(--color-text-muted);
font-size: 1rem;
font-weight: 400;
}
.plugin-preview__surface {
margin-top: var(--space-4);
}
/* --- Plugin administration (issue #72) ------------------------------------ */
.plugin-manager__upload-input {
display: none;
}
.plugin-manager__list {
list-style: none;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--space-3);
}
.plugin-manager__item {
border: 1px solid var(--color-border);
border-radius: 6px;
padding: var(--space-3);
}
.plugin-manager__head {
display: flex;
align-items: baseline;
gap: var(--space-2);
}
.plugin-manager__name {
font-weight: 600;
}
.plugin-manager__version,
.plugin-manager__kind {
color: var(--color-text-muted);
font-size: 0.875rem;
}
.plugin-manager__permissions {
margin: var(--space-2) 0;
font-size: 0.875rem;
}
.plugin-manager__permission {
margin-right: var(--space-1);
}
.plugin-manager__controls {
display: flex;
align-items: center;
gap: var(--space-3);
flex-wrap: wrap;
}
.plugin-manager__mode-hint {
color: var(--color-text-muted);
font-size: 0.8125rem;
}
.pond-plugins__list {
list-style: none;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--space-2);
}
.pond-plugins__version {
color: var(--color-text-muted);
font-size: 0.875rem;
}