Files
VoxVera/site/nostr-client.css
T
thePR0M3TH3ANandClaude Opus 4.8 9b03ada43a Flyers: edit, re-publish (keep-alive), and delete (tombstone + NIP-09)
Authors can now manage a published flyer from the editor when it's loaded from
an event (author-only — the active signing key must match the flyer's author):

- Edit: change fields and publish again; the same d-tag replaces in place.
- Re-publish (keep-alive): re-sign + re-broadcast the current content so relays
  that prune app-data don't age the flyer out. Partially addresses roadmap #4.
- Delete: belt-and-suspenders across relay behaviors —
  1) a replaceable TOMBSTONE (same kind+d, payload deleted:true + a ["deleted"]
     tag) that overwrites the flyer's content, so the board/viewer hide it even
     on relays that ignore deletions, and
  2) a NIP-09 deletion request (kind 5) for the addressable a-tag + event id.
  Confirmed via a modal; framed as best-effort, not a guarantee.

Tombstone recognition: the board's parseFlyers keeps the newest event per
(pubkey, d) and skips it when that newest version is a tombstone (so a delete
can't be reversed by an older copy arriving later); the viewer renders a
localized "This flyer was removed." state.

Adds the loaded-flyer actions UI + a delete-confirm modal, 11 new strings ×
14 languages, a Python schema test for the tombstone payload, and e2e for the
delete flow, board hiding, and the viewer removed state. 216 e2e across all six
engines; docs (spec/roadmap/README) updated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 19:39:23 -04:00

1402 lines
23 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
:root {
color-scheme: light;
--ink: #111;
--muted: #5b5b5b;
--line: #c9c9c9;
--soft: #f3f3f1;
--accent: #b80000;
--ok: #1d6b3a;
--warn: #8a4d00;
/* Printable sheet dimensions. Switched by the paper-* class on <html>
(applyPaperSize in nostr-client.js). The tear-off column (3.75in) and QR
codes (1.25in) stay fixed physical sizes; the content column flexes. */
--sheet-w: 8.5in;
--sheet-h: 11in;
}
html.paper-letter {
--sheet-w: 8.5in;
--sheet-h: 11in;
}
html.paper-a4 {
--sheet-w: 210mm;
--sheet-h: 297mm;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
color: var(--ink);
background: #fff;
font-family: "Courier New", Courier, monospace;
line-height: 1.45;
}
button,
input,
select,
textarea {
font: inherit;
}
button {
min-height: 40px;
padding: 8px 14px;
border: 1px solid #000;
background: #000;
color: #fff;
cursor: pointer;
}
button:hover {
background: #333;
}
.secondary-button {
background: #fff;
color: #000;
}
.secondary-button:hover {
background: #eee;
}
.topbar {
display: flex;
gap: 24px;
justify-content: space-between;
align-items: flex-end;
padding: 20px clamp(16px, 4vw, 42px);
border-bottom: 2px solid #000;
}
.topbar h1,
.topbar p,
.section-title h2,
.preview-toolbar h2 {
margin: 0;
}
.topbar h1 {
font-size: 24px;
}
.topbar p {
color: var(--muted);
}
.mode-tabs {
display: inline-flex;
border: 1px solid #000;
}
.topbar-controls {
display: flex;
gap: 10px;
align-items: center;
justify-content: flex-end;
flex-wrap: wrap;
}
.topbar-controls select {
width: auto;
min-height: 40px;
max-width: 220px;
}
/* Wider so the full paper size (e.g. "US Letter (8.5 × 11 in)") is readable. */
#topbar-paper,
#viewer-paper {
min-width: 210px;
max-width: 260px;
}
.tab {
border: 0;
border-right: 1px solid #000;
background: #fff;
color: #000;
}
.tab:last-child {
border-right: 0;
}
.tab.active {
background: #000;
color: #fff;
}
main {
padding: 18px clamp(16px, 4vw, 42px) 36px;
}
.panel {
display: none;
}
.panel.active {
display: block;
}
.viewer-floating {
display: none;
}
.workspace {
display: grid;
grid-template-columns: minmax(320px, 1.15fr) minmax(280px, 0.85fr);
gap: 24px;
align-items: start;
}
.editor-form,
.result-panel {
min-width: 0;
}
.section-title,
.preview-toolbar {
display: flex;
gap: 16px;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.state-pill {
display: inline-block;
padding: 4px 8px;
border: 1px solid var(--line);
color: var(--muted);
font-size: 12px;
}
.identity-row {
display: flex;
flex-wrap: wrap;
gap: 10px;
align-items: center;
margin: 0 0 12px;
}
.identity-row .secondary-button {
min-height: 32px;
padding: 5px 10px;
font-size: 12px;
}
/* Identity mode controls (anonymous / NIP-07 / imported nsec). */
.identity-controls {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 0 0 10px;
}
.identity-controls .secondary-button {
min-height: 32px;
padding: 5px 10px;
font-size: 12px;
}
/* Vertical stack so the input, the "remember" checkbox, the PIN field, and the
action button each get their own line (a wrapping row collided the label and
button). */
.identity-import {
display: flex;
flex-direction: column;
align-items: stretch;
gap: 8px;
margin: 0 0 12px;
padding: 12px;
border: 1px solid var(--line);
border-radius: 6px;
background: var(--soft);
}
.identity-import input[type="password"] {
width: 100%;
box-sizing: border-box;
font: inherit;
padding: 6px 8px;
border: 1px solid var(--line);
border-radius: 6px;
}
.identity-import .secondary-button {
align-self: flex-start;
min-height: 32px;
padding: 5px 12px;
font-size: 12px;
}
.identity-import .nsec-remember-row {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--muted);
}
.identity-import .nsec-remember-row input {
width: auto;
flex: 0 0 auto;
margin: 0;
}
/* The locked row keeps the note on its own line, then PIN + buttons below. */
#identity-locked-row {
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
#identity-locked-note {
font-size: 12px;
color: var(--muted);
flex: 1 1 100%;
}
#identity-locked-row input[type="password"] {
width: auto;
flex: 1 1 160px;
}
.editor-form label {
display: grid;
gap: 5px;
margin-bottom: 12px;
font-size: 13px;
font-weight: 700;
}
input,
select,
textarea {
width: 100%;
border: 1px solid #000;
border-radius: 0;
background: #fff;
color: #000;
padding: 8px;
}
textarea {
resize: vertical;
}
.field-grid {
display: grid;
grid-template-columns: minmax(0, 1fr) 120px;
gap: 12px;
}
.actions {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 14px;
}
.result-list {
display: grid;
grid-template-columns: 90px minmax(0, 1fr);
gap: 8px 12px;
margin: 0 0 12px;
}
.result-list dt {
font-weight: 700;
}
.result-list dd {
margin: 0;
min-width: 0;
}
.copy-value {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 8px;
align-items: start;
}
.copy-button {
min-height: 28px;
padding: 4px 8px;
font-size: 11px;
}
.relay-results {
display: grid;
gap: 4px;
}
.relay-ok {
color: var(--ok);
font-weight: 700;
}
.relay-error {
color: var(--warn);
}
code {
display: block;
overflow-wrap: anywhere;
white-space: normal;
}
.status-line {
min-height: 22px;
color: var(--muted);
}
.field-error {
margin: 0;
color: var(--warn);
font-size: 12px;
font-weight: 700;
}
.preview-band {
margin-top: 26px;
border-top: 2px solid #000;
padding-top: 18px;
}
.flyer-preview {
overflow-x: auto;
padding-bottom: 8px;
}
.flyer-sheet {
display: flex;
width: var(--sheet-w);
height: var(--sheet-h);
border: 1px solid #000;
background: #fff;
color: #000;
overflow: hidden;
}
.flyer-sheet.no-tear-offs .tear-offs {
display: none;
}
.flyer-sheet.no-tear-offs .flyer-content {
width: 100%;
}
.tear-offs {
width: 3.75in;
padding: 8px;
border-right: 1px dashed #000;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 5px;
}
.tear-off {
display: flex;
gap: 12px;
height: 1in;
padding: 5px;
border: 1px dashed #000;
font-size: 10px;
overflow: hidden;
}
.qr-box {
flex: 0 0 0.72in;
width: 0.72in;
height: 0.72in;
border: 1px solid #000;
display: grid;
place-items: center;
font-size: 9px;
text-align: center;
}
.flyer-content {
width: 4.75in;
padding: 0.28in;
display: flex;
flex-direction: column;
justify-content: flex-start;
text-align: center;
}
.flyer-content h1 {
margin: 0 0 0.18in;
font-size: 34px;
line-height: 1.05;
}
.flyer-content .subtitle {
margin-bottom: 0.16in;
color: var(--accent);
font-weight: 700;
font-size: 21px;
}
.message {
margin-top: 0.12in;
text-align: left;
font-size: 15px;
white-space: pre-wrap;
}
.main-qr {
align-self: center;
margin-top: 0.18in;
width: 1.25in;
height: 1.25in;
}
.footer {
margin-top: auto;
font-size: 11px;
overflow-wrap: anywhere;
}
a {
color: var(--accent);
}
.container {
display: flex;
flex-direction: row;
width: var(--sheet-w);
height: var(--sheet-h);
border: 1px solid #000;
background: #fff;
color: #000;
box-sizing: border-box;
overflow: hidden;
page-break-inside: avoid;
/* Per-script letter-spacing, set by the ls-* policy class (see
LETTER_SPACING_POLICY in nostr-client.js). Defaults below match the
historical design and act as a safe fallback if no policy class is set. */
--ls-display: 2px;
--ls-subtitle: 6px;
--ls-body: 0;
--ls-url: 0;
--ls-footer: 0;
}
/* Latin, Cyrillic, Hebrew: tighten tracking to reclaim line space. */
.container.ls-full {
--ls-display: 0.5px;
--ls-subtitle: 2px;
--ls-body: -0.3px;
--ls-url: -0.3px;
--ls-footer: 0;
}
/* CJK: tracking is safe but must never go negative (glyphs would overlap). */
.container.ls-cjk {
--ls-display: 0;
--ls-subtitle: 0;
--ls-body: 0;
--ls-url: 0;
--ls-footer: 0;
}
/* Arabic, Persian, Hindi: letter-spacing breaks shaping — turn it off. */
.container.ls-none {
--ls-display: normal;
--ls-subtitle: normal;
--ls-body: normal;
--ls-url: normal;
--ls-footer: normal;
}
.container.no-tear-offs .left-tear-offs {
display: none;
}
.container.no-tear-offs .content {
width: 100%;
}
.left-tear-offs {
width: 3.75in;
padding: 8px;
border-right: 1px dashed #000;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 5px;
box-sizing: border-box;
}
.tear-off-text {
flex: 1;
min-width: 0;
padding-top: 1px;
overflow-wrap: anywhere;
word-break: normal;
hyphens: none;
display: flex;
flex-direction: column;
}
.tear-off-event-id {
margin-top: auto;
padding-top: 4px;
font-size: 8px;
line-height: 1.2;
word-break: break-all;
overflow-wrap: anywhere;
}
.tear-off-event-id-value {
display: block;
font-family: "Courier New", monospace;
font-size: 12px;
line-height: 1.1;
letter-spacing: -0.2px;
word-break: break-all;
}
.qr-code {
width: 80px;
height: 80px;
flex-shrink: 0;
}
.qr-code svg {
display: block;
width: 100%;
height: 100%;
}
.qr-error {
display: grid;
width: 100%;
height: 100%;
place-items: center;
border: 1px solid #000;
font-size: 9px;
text-align: center;
}
.qr-placeholder {
width: 80px;
height: 80px;
flex-shrink: 0;
background:
linear-gradient(90deg, #000 8px, transparent 8px 16px, #000 16px 24px, transparent 24px 32px),
linear-gradient(#000 8px, transparent 8px 16px, #000 16px 24px, transparent 24px 32px);
background-color: #fff;
background-size: 32px 32px;
border: 8px solid #000;
}
.content {
width: calc(var(--sheet-w) - 3.75in);
padding: 15px 20px;
text-align: center;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: flex-start;
page-break-inside: avoid;
overflow-wrap: break-word;
}
.flyer-status-message {
margin: auto;
padding: 0 10px;
font-size: 20px;
font-weight: 700;
line-height: 1.3;
text-align: center;
letter-spacing: var(--ls-display);
}
.content h1 {
margin: 0;
padding: 0;
font-size: 24px;
line-height: 1.2;
letter-spacing: var(--ls-display);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
}
.distribute {
font-size: 18px;
line-height: 1.2;
letter-spacing: var(--ls-subtitle);
margin: 2px 0;
padding: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
}
.container .message {
flex: 1;
margin-top: 4px;
font-size: 14px;
line-height: 1.4;
letter-spacing: var(--ls-body);
text-align: left;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: flex-start;
white-space: pre-wrap;
box-sizing: border-box;
position: relative;
}
.qr-code-body {
width: 100%;
height: auto;
display: flex;
justify-content: flex-start;
align-items: center;
gap: 10px;
margin-top: 10px;
padding: 0;
box-sizing: border-box;
}
.qr-code-body .main-qr {
width: 80px;
height: 80px;
}
.qr-code-url {
font-size: 12px;
letter-spacing: var(--ls-url);
text-align: left;
overflow-wrap: anywhere;
word-break: normal;
hyphens: none;
flex: 1 1 auto;
min-width: 0;
padding-left: 4px;
}
hr {
border: none;
border-top: 1px solid #000;
width: 100%;
margin: 4px 0;
}
.container .footer {
font-size: 10px;
overflow-wrap: break-word;
text-align: center;
align-self: center;
width: 100%;
padding: 10px 0;
box-sizing: border-box;
border-top: 1px solid #000;
}
.container .footer p {
margin: 0;
padding: 0;
}
.container .footer .binary {
margin-bottom: 8px;
margin-top: 10px;
letter-spacing: var(--ls-footer);
}
.container .footer .credit {
font-size: 12px;
margin-top: 0;
}
/* Screen-only link to the bulletin board, shown below the flyer preview
(outside the printed sheet). Hidden in print (see @media print). */
.preview-band > .board-link {
text-align: center;
font-size: 13px;
margin: 12px 0;
}
.board-link a {
color: var(--accent);
}
body.mode-viewer {
background: #fff;
}
body.mode-viewer .topbar,
body.mode-viewer #editor-panel,
body.mode-viewer .preview-toolbar {
display: none;
}
body.mode-viewer main {
padding: 0;
}
body.mode-viewer .preview-band {
margin: 0;
padding: 0;
border: 0;
}
body.mode-viewer .flyer-preview {
display: flex;
justify-content: center;
align-items: flex-start;
min-height: 100vh;
padding: 0 0 20px;
overflow: auto;
}
body.mode-viewer .viewer-floating {
position: sticky;
top: 0;
z-index: 20;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: 8px;
width: 100%;
padding: 12px;
background: #fff;
}
body.mode-viewer .viewer-floating button {
min-height: 34px;
padding: 6px 10px;
font-size: 12px;
}
body.mode-viewer .viewer-floating select {
width: auto;
min-height: 34px;
max-width: 180px;
padding: 6px 8px;
font-size: 12px;
background: #fff;
}
body.mode-viewer #viewer-panel {
display: none;
}
body.mode-viewer #viewer-panel.drawer-open {
position: fixed;
top: 56px;
right: 12px;
bottom: 12px;
z-index: 19;
display: block;
width: min(680px, calc(100vw - 24px));
overflow: auto;
padding: 16px;
border: 2px solid #000;
background: #fff;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}
body.mode-viewer #viewer-panel.drawer-open .workspace {
display: block;
}
body.mode-viewer #viewer-panel.drawer-open .result-panel {
margin-top: 18px;
}
@media (max-width: 900px) {
body {
font-size: 16px;
}
.topbar {
display: block;
padding: 14px;
}
.topbar h1 {
font-size: 20px;
}
.topbar p {
margin-top: 4px;
font-size: 13px;
}
.topbar-controls {
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 8px;
margin-top: 12px;
}
.topbar-controls select {
width: 100%;
max-width: none;
}
.mode-tabs {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
width: 100%;
margin-top: 0;
}
.tab {
min-height: 44px;
}
main {
padding: 12px;
}
.workspace,
.field-grid {
display: block;
}
.section-title,
.preview-toolbar {
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 8px;
}
.identity-row {
align-items: stretch;
}
.identity-row .state-pill,
.identity-row .secondary-button {
width: 100%;
}
input,
select,
textarea {
min-height: 44px;
padding: 10px;
font-size: 16px;
}
textarea {
min-height: 120px;
}
.actions {
display: grid;
grid-template-columns: minmax(0, 1fr);
}
.actions button,
.preview-toolbar button {
width: 100%;
min-height: 44px;
}
.result-panel {
margin-top: 18px;
}
.result-list {
display: block;
}
.result-list dt {
margin-top: 10px;
}
.copy-value {
grid-template-columns: minmax(0, 1fr);
}
.copy-button {
width: 100%;
min-height: 36px;
}
.preview-band {
margin-top: 18px;
padding-top: 12px;
}
.flyer-preview {
--mobile-flyer-scale: var(--flyer-preview-scale, 0.58);
width: 100%;
min-height: var(--flyer-preview-height, calc(1056px * var(--mobile-flyer-scale)));
overflow: hidden;
padding: 0;
}
.flyer-sheet,
.container {
transform: scale(var(--mobile-flyer-scale));
transform-origin: top left;
margin-bottom: var(--flyer-preview-collapse, calc((1056px * var(--mobile-flyer-scale)) - 1056px));
}
body.mode-viewer .viewer-floating {
position: sticky;
top: 0;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 6px;
padding: 8px;
}
body.mode-viewer .viewer-floating button,
body.mode-viewer .viewer-floating select {
width: 100%;
max-width: none;
min-height: 40px;
font-size: 12px;
}
body.mode-viewer .viewer-floating select {
grid-column: 1 / -1;
}
body.mode-viewer .flyer-preview {
justify-content: flex-start;
min-height: 0;
padding: 0;
overflow: hidden;
}
body.mode-viewer #viewer-panel.drawer-open {
top: 96px;
right: 8px;
bottom: 8px;
width: calc(100vw - 16px);
padding: 12px;
}
}
@media print {
/* @page size is injected by applyPaperSize() in nostr-client.js (Letter or
A4) since @page cannot read CSS custom properties across engines. This
rule is the margin fallback and the default size before JS runs. */
@page {
size: Letter portrait;
margin: 0;
}
html,
body {
width: var(--sheet-w);
height: var(--sheet-h);
margin: 0;
padding: 0;
overflow: hidden;
}
body > header,
body > .viewer-floating,
.viewer-floating,
.viewer-floating *,
.board-link,
.modal-overlay,
#open-viewer-controls,
#viewer-print,
#viewer-editor,
#viewer-lang,
body > main > .panel,
.preview-toolbar,
.viewer-drawer {
display: none !important;
}
main {
display: block;
width: var(--sheet-w);
height: var(--sheet-h);
padding: 0;
margin: 0;
}
.preview-band {
display: block;
width: var(--sheet-w);
height: var(--sheet-h);
border: 0;
margin: 0;
padding: 0;
}
.flyer-preview {
display: block;
width: var(--sheet-w);
height: var(--sheet-h);
overflow: visible;
padding: 0;
margin: 0;
}
.flyer-sheet,
.container {
position: absolute;
inset: 0 auto auto 0;
width: var(--sheet-w);
height: var(--sheet-h);
transform: none;
margin: 0;
border: 0;
}
}
/* ---- Bulletin board page (board.html) ---- */
.board-main {
max-width: 1000px;
margin: 0 auto;
padding: 24px 20px 48px;
}
.board-back {
color: var(--accent);
text-decoration: none;
font-weight: 700;
}
#board-status {
color: var(--muted);
margin: 8px 0 16px;
}
.board-table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
.board-table th,
.board-table td {
text-align: left;
padding: 8px 10px;
border-bottom: 1px solid var(--line);
vertical-align: top;
}
.board-table thead th {
position: sticky;
top: 0;
background: var(--soft);
cursor: pointer;
user-select: none;
white-space: nowrap;
}
.board-table thead th .sort-indicator {
color: var(--muted);
font-size: 11px;
}
.board-table tbody tr:hover {
background: #faf7f7;
}
.board-table .board-title {
font-weight: 700;
overflow-wrap: anywhere;
}
.board-table .board-npub {
font-family: "Courier New", monospace;
font-size: 12px;
white-space: nowrap;
}
.board-table .board-date {
white-space: nowrap;
color: var(--muted);
}
.board-table .board-eventid {
font-family: "Courier New", monospace;
font-size: 12px;
white-space: nowrap;
}
.board-table .board-copy {
margin-inline-start: 6px;
font: inherit;
font-size: 11px;
padding: 2px 8px;
border: 1px solid var(--line);
border-radius: 6px;
background: transparent;
color: var(--accent);
cursor: pointer;
white-space: nowrap;
}
.board-table a {
color: var(--accent);
}
/* ---- Bulletin board login gate (NIP-07) ---- */
.board-gate {
max-width: 520px;
margin: 48px auto;
text-align: center;
}
.board-gate h2 {
margin: 0 0 8px;
font-size: 22px;
}
.board-gate p {
color: var(--muted);
margin: 0 0 20px;
line-height: 1.4;
}
.board-connect {
font: inherit;
font-weight: 700;
padding: 10px 24px;
border: none;
border-radius: 6px;
background: var(--accent);
color: #fff;
cursor: pointer;
}
.board-connect:disabled {
opacity: 0.6;
cursor: default;
}
.board-gate-error {
color: #8a4d00;
margin: 16px 0 0;
}
.board-connect-methods {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
}
.board-connect-alt {
font: inherit;
font-size: 14px;
padding: 8px 18px;
border: 1px solid var(--line);
border-radius: 6px;
background: transparent;
color: var(--accent);
cursor: pointer;
}
.board-nsec-row,
.board-generated {
max-width: 420px;
margin: 18px auto 0;
text-align: left;
}
.board-nsec-row input,
.board-key-field input {
width: 100%;
box-sizing: border-box;
font: inherit;
padding: 8px 10px;
border: 1px solid var(--line);
border-radius: 6px;
}
.board-nsec-row .board-connect {
margin-top: 8px;
}
.board-key-note {
color: var(--muted);
font-size: 12px;
margin: 8px 0 0;
}
.board-key-warning {
color: #8a4d00;
font-size: 13px;
margin: 0 0 12px;
line-height: 1.4;
}
.board-key-field {
display: block;
font-size: 12px;
color: var(--muted);
margin: 0 0 10px;
}
.board-key-field input {
margin-top: 4px;
font-family: "Courier New", monospace;
}
.board-key-secret {
display: flex;
gap: 6px;
align-items: stretch;
}
.board-key-secret input {
flex: 1;
}
.board-identity {
display: inline-flex;
align-items: center;
gap: 8px;
}
/* The `hidden` attribute must win over the display rule above. */
.board-identity[hidden] {
display: none;
}
.board-identity .board-npub {
font-family: "Courier New", monospace;
font-size: 12px;
color: var(--muted);
}
.board-disconnect {
font: inherit;
font-size: 13px;
padding: 4px 10px;
border: 1px solid var(--line);
border-radius: 6px;
background: transparent;
color: var(--accent);
cursor: pointer;
}
/* Web-of-trust filter bar above the board table. */
.board-filter {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
flex-wrap: wrap;
margin: 4px 0 12px;
}
.board-filter-note {
color: var(--muted);
font-size: 13px;
}
.board-show-all {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 13px;
cursor: pointer;
white-space: nowrap;
}
/* ---- Publish confirmation modal ---- */
.modal-overlay {
position: fixed;
inset: 0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
background: rgba(0, 0, 0, 0.5);
}
.modal-overlay[hidden] {
display: none;
}
.modal {
background: #fff;
color: var(--ink);
width: 100%;
max-width: 440px;
padding: 24px;
border-radius: 8px;
border: 1px solid var(--line);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
}
.modal h2 {
margin: 0 0 8px;
font-size: 20px;
}
.modal p {
margin: 0 0 14px;
color: var(--muted);
}
.modal-url-row {
display: flex;
gap: 8px;
margin-bottom: 18px;
}
.modal-url-row input {
flex: 1;
min-width: 0;
padding: 8px 10px;
font-family: "Courier New", monospace;
font-size: 13px;
border: 1px solid var(--line);
border-radius: 4px;
}
.modal-url-row button {
white-space: nowrap;
}
.modal-close {
display: block;
margin-left: auto;
}
.modal-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 16px;
}
/* Destructive action (delete). */
.secondary-button.danger {
border-color: var(--accent);
color: var(--accent);
}
.secondary-button.danger:hover {
background: var(--accent);
color: #fff;
}
#loaded-flyer-status {
color: var(--muted);
}