xref: /plugin/annotations/style.css (revision ad1073d40e87e01426f7a3b1bf49fa2e56d38cf1)
1/**
2 * Annotations plugin — stylesheet.
3 *
4 * Colour tokens use DokuWiki's __xxx__ replacement syntax so the theme
5 * controls the palette.  Hard-coded colours are limited to the annotation-
6 * specific highlights (amber / green) which are intentionally opinionated.
7 *
8 * FF78 ESR safe: no :has(), :not() with selectors, aspect-ratio, container
9 * queries, or CSS nesting.
10 *
11 * The two highlight hues are driven by CSS custom properties that action.php
12 * injects from the color_open / color_resolved config (as "r,g,b" triplets);
13 * every fill/border/marker/pill tint below is that hue at a different opacity.
14 * The :root fallbacks here keep the built-in amber/green palette when the
15 * injected <style> is absent (e.g. annotations off, or a stripped template).
16 *
17 * NOTE: every rgba() that contains var() is LESS-escaped as ~"rgba(var(…), a)".
18 * DokuWiki compiles plugin CSS through lesserphp, which otherwise evaluates
19 * rgba() at compile time, reads var() as 0, and bakes the colour to #000000.
20 * The escape makes lesserphp emit the declaration verbatim so the browser
21 * resolves the custom property at render time. Keep new var()-based colours
22 * escaped the same way.
23 */
24
25:root {
26    --ann-open-rgb: 245, 158, 11;     /* amber — open / unresolved (config default) */
27    --ann-resolved-rgb: 74, 222, 128; /* green — resolved (config default) */
28}
29
30/* =========================================================================
31   Highlight spans
32   ========================================================================= */
33
34.ann-highlight-open {
35    background-color: ~"rgba(var(--ann-open-rgb), 0.35)";   /* amber-300 @ 35% */
36    border-bottom: 2px solid ~"rgba(var(--ann-open-rgb), 0.7)";
37    border-radius: 2px;
38    cursor: pointer;
39    transition: background-color 0.15s ease;
40}
41
42.ann-highlight-open:hover {
43    background-color: ~"rgba(var(--ann-open-rgb), 0.55)";
44}
45
46.ann-highlight-resolved {
47    background-color: ~"rgba(var(--ann-resolved-rgb), 0.30)";  /* green-300 @ 30% */
48    border-bottom: 2px solid ~"rgba(var(--ann-resolved-rgb), 0.6)";
49    border-radius: 2px;
50    cursor: pointer;
51    transition: background-color 0.15s ease;
52}
53
54.ann-highlight-resolved:hover {
55    background-color: ~"rgba(var(--ann-resolved-rgb), 0.50)";
56}
57
58/* =========================================================================
59   Counter bar
60   ========================================================================= */
61
62#ann-counter-bar {
63    display: flex;
64    align-items: center;
65    flex-wrap: wrap;
66    gap: 0.5em;
67    padding: 0.4em 0.75em;
68    margin-bottom: 0.75em;
69    background: __background_alt__;
70    border: 1px solid __border__;
71    border-radius: 4px;
72    color: __text__;
73}
74
75.ann-orphan-link {
76    color: __link__;
77    text-decoration: underline;
78    cursor: pointer;
79}
80
81/* =========================================================================
82   Gutter markers
83   ========================================================================= */
84
85/* Markers are appended to document.body as position:absolute elements so
86   that no template overflow:hidden can clip them. Top/left are set inline
87   via JS using getBoundingClientRect() + scroll offsets. All markers share
88   the same X position (left edge of the .page column) so they form a tidy
89   vertical column in the document margin. */
90.ann-gutter-marker {
91    position: absolute;
92    padding: 0;
93    border: none;
94    background: none;
95    color: ~"rgba(var(--ann-open-rgb), 0.8)"; /* amber — open */
96    cursor: pointer;
97    display: flex;
98    align-items: center;
99    justify-content: center;
100    z-index: 1000;
101    transition: color 0.15s ease, transform 0.12s ease;
102}
103
104/* Suppress any UA button background on all interactive states. */
105.ann-gutter-marker:hover,
106.ann-gutter-marker:focus,
107.ann-gutter-marker:active {
108    background: none;
109    outline: none;
110    box-shadow: none;
111}
112
113.ann-gutter-marker:hover {
114    color: ~"rgba(var(--ann-open-rgb), 1)";
115}
116
117.ann-gutter-marker[data-status="resolved"] {
118    color: ~"rgba(var(--ann-resolved-rgb), 0.8)"; /* green — resolved */
119}
120
121.ann-gutter-marker[data-status="resolved"]:hover {
122    color: ~"rgba(var(--ann-resolved-rgb), 1)";
123}
124
125/* =========================================================================
126   Annotation panel
127   ========================================================================= */
128
129.ann-panel {
130    margin: 0.75em 0 1em;
131    border: 1px solid __border__;
132    border-left: 3px solid ~"rgba(var(--ann-open-rgb), 0.7)";
133    background: __background_alt__;
134    box-shadow: 0 2px 8px rgba(0,0,0,0.10);
135    contain: layout;
136}
137
138/* =========================================================================
139   Thread entries (annotation + replies)
140   ========================================================================= */
141
142.ann-thread-entry {
143    padding: 0.65em 0.85em;
144    border-bottom: 1px solid __border__;
145}
146
147.ann-thread-entry:last-of-type {
148    border-bottom: none;
149}
150
151/* Root annotation entry: lighter background so it stands out from the panel. */
152.ann-thread-entry.ann-annotation {
153    background: __background__;
154}
155
156/* Reply entries: inset card with the same lighter background. */
157.ann-reply {
158    margin-left: 1.5em;
159    background: __background__;
160    border-left: 2px solid __border__;
161}
162
163/* =========================================================================
164   Meta row (avatar, author, time, status, close button)
165   ========================================================================= */
166
167.ann-meta {
168    display: flex;
169    align-items: center;
170    gap: 0.4em;
171    margin-bottom: 0.35em;
172    flex-wrap: wrap;
173}
174
175.ann-avatar {
176    display: inline-flex;
177    align-items: center;
178    justify-content: center;
179    width: 1.8em;
180    height: 1.8em;
181    border-radius: 50%;
182    background: __link__;
183    color: #fff;
184    font-size: 0.75em;
185    font-weight: 700;
186    flex-shrink: 0;
187}
188
189.ann-author {
190    font-weight: 600;
191    color: __text__;
192}
193
194.ann-time {
195    color: __text_alt__;
196    font-size: 0.85em;
197}
198
199.ann-status {
200    display: inline-block;
201    padding: 0.1em 0.45em;
202    border-radius: 10em;
203    font-size: 0.78em;
204    font-weight: 600;
205    letter-spacing: 0.02em;
206}
207
208.ann-status-open {
209    background: ~"rgba(var(--ann-open-rgb), 0.25)";
210    color: #92400e;
211    border: 1px solid ~"rgba(var(--ann-open-rgb), 0.5)";
212}
213
214.ann-status-resolved {
215    background: ~"rgba(var(--ann-resolved-rgb), 0.25)";
216    color: #166534;
217    border: 1px solid ~"rgba(var(--ann-resolved-rgb), 0.4)";
218}
219
220/* =========================================================================
221   Body text and quoted selection
222   ========================================================================= */
223
224.ann-body {
225    white-space: pre-wrap;
226    word-break: break-word;
227    color: __text__;
228    margin-bottom: 0.4em;
229}
230
231.ann-quote {
232    margin-bottom: 0.65em;
233    padding: 0.25em 0.6em;
234    border-left: 3px solid ~"rgba(var(--ann-open-rgb), 0.6)";
235    color: __text__;
236    font-size: 0.9em;
237    background: ~"rgba(var(--ann-open-rgb), 0.08)";
238    border-radius: 0 2px 2px 0;
239}
240
241/* =========================================================================
242   Action buttons row
243   ========================================================================= */
244
245.ann-actions {
246    display: flex;
247    gap: 0.5em;
248    flex-wrap: wrap;
249    margin-top: 0.65em;
250}
251
252.ann-btn {
253    display: inline-block;
254    padding: 0.2em 0.55em;
255    font-size: 0.85em;
256    border: 1px solid __border__;
257    border-radius: 3px;
258    background: __background__ !important;
259    color: __text__;
260    cursor: pointer;
261    line-height: 1.4;
262    transition: background-color 0.12s ease;
263}
264
265.ann-btn:hover {
266    background: __background_alt__ !important;
267}
268
269.ann-btn-primary {
270    background: __link__ !important;
271    border-color: __link__;
272    color: #fff;
273}
274
275.ann-btn-primary:hover {
276    background: __link__ !important;
277    color: #fff;
278    opacity: 0.88;
279}
280
281/* Disabled state: prevent UA-stylesheet background overrides and ensure
282   primary buttons keep their link colour. */
283.ann-btn:disabled,
284.ann-btn[disabled] {
285    background: __background__;
286    opacity: 0.55;
287    cursor: not-allowed;
288}
289
290.ann-btn:disabled:hover,
291.ann-btn[disabled]:hover {
292    background: __background__;
293}
294
295.ann-btn-primary:disabled,
296.ann-btn-primary[disabled] {
297    background: __link__;
298    color: #fff;
299}
300
301.ann-btn-primary:disabled:hover,
302.ann-btn-primary[disabled]:hover {
303    background: __link__;
304    opacity: 0.55;
305}
306
307/* Spinner shown while an AJAX request is in flight (set by setBusy()).
308   The translate(-50%,-50%) is baked into every keyframe so it stays perfectly
309   centred regardless of sub-pixel rounding and never jigles. */
310@keyframes ann-spin {
311    from { transform: translate(-50%, -50%) rotate(0deg); }
312    to   { transform: translate(-50%, -50%) rotate(360deg); }
313}
314
315.ann-btn-busy {
316    position: relative;
317    color: transparent;
318}
319
320.ann-btn-busy::after {
321    content: '';
322    position: absolute;
323    top: 50%;
324    left: 50%;
325    width: 0.75em;
326    height: 0.75em;
327    border: 2px solid rgba(0, 0, 0, 0.25);
328    border-top-color: rgba(0, 0, 0, 0.75);
329    border-radius: 50%;
330    animation: ann-spin 0.6s linear infinite;
331}
332
333.ann-btn-primary.ann-btn-busy::after {
334    border-color: rgba(255, 255, 255, 0.35);
335    border-top-color: rgba(255, 255, 255, 0.9);
336}
337
338.ann-btn-danger {
339    border-color: #dc2626;
340    color: #dc2626;
341}
342
343.ann-btn-danger:hover {
344    background: rgba(220, 38, 38, 0.08);
345}
346
347.ann-btn-admin {
348    border-color: __border__;
349    color: __text__;
350}
351
352/* Close button — lives inside .ann-meta, pushed right via margin-left:auto (set in JS). */
353.ann-close {
354    font-size: 1.35em;
355    line-height: 1;
356    padding: 0.05em 0.3em;
357    border: none;
358    background: none !important;
359    color: __text_alt__;
360    cursor: pointer;
361    flex-shrink: 0;
362}
363
364.ann-close:hover {
365    color: __text__;
366    background: none !important;
367}
368
369/* =========================================================================
370   Reply form + new-annotation form
371   ========================================================================= */
372
373.ann-reply-form,
374.ann-new-form {
375    padding: 0.65em 0.85em;
376}
377
378.ann-new-form {
379    margin: 0.75em 0 1em;
380    border: 1px solid __border__;
381    border-left: 3px solid ~"rgba(var(--ann-open-rgb), 0.7)";
382    background: __background_alt__;
383    contain: layout;
384}
385
386.ann-body-input {
387    display: block;
388    width: 100%;
389    box-sizing: border-box;
390    padding: 0.4em 0.6em;
391    font: inherit;
392    border: 1px solid __border__;
393    background: __background__;
394    color: __text__;
395    resize: vertical;
396    margin-bottom: 0.65em;
397}
398
399.ann-body-input:focus {
400    outline: 1px solid __link__;
401}
402
403.ann-form-row {
404    display: flex;
405    gap: 0.4em;
406}
407
408.ann-form-row + .ann-quote {
409    margin-top: 0.65em;
410}
411
412/* =========================================================================
413   Selection tooltip
414   ========================================================================= */
415
416.ann-tooltip {
417    position: absolute;
418    z-index: 9000;
419    border-radius: 4px;
420    box-shadow: 0 2px 8px rgba(0,0,0,0.15);
421}
422
423/* Static amber glow drawing the eye to the freshly-revealed "Annotate" button.
424   The rgba() is LESS-escaped (~"…") so DokuWiki's CSS compiler passes it through
425   verbatim instead of evaluating var() to black; the browser resolves the
426   custom property at render time. FF78 ESR safe. */
427.ann-tooltip .ann-btn {
428    box-shadow: 0 0 8px 2px ~"rgba(var(--ann-open-rgb), 0.45)", 0 1px 4px rgba(0,0,0,0.25);
429}
430
431/* =========================================================================
432   Orphan drawer
433   ========================================================================= */
434
435.ann-orphan-drawer {
436    display: flow-root; /* BFC: shrinks to avoid overlapping the floated TOC */
437    margin-bottom: 0.65em;
438    padding: 0.75em 1em;
439    border: 1px dashed __border__;
440    border-radius: 4px;
441    background: __background_alt__;
442}
443
444.ann-orphan-drawer h4 {
445    margin: 0 0 0.3em;
446    font-size: 0.95em;
447    color: __text__;
448}
449
450.ann-orphan-note {
451    font-size: 0.85em;
452    color: __text__;
453    margin-bottom: 0.75em;
454}
455
456/* Each orphaned annotation renders as a full thread (root + replies). Wrap it
457   like an inline panel so multiple orphaned threads stay visually separated. */
458.ann-orphan-thread {
459    margin-bottom: 0.75em;
460    border: 1px solid __border__;
461    border-left: 3px solid ~"rgba(var(--ann-open-rgb), 0.7)";
462    background: __background_alt__;
463    contain: layout;
464}
465
466.ann-orphan-thread:last-child {
467    margin-bottom: 0;
468}
469
470.ann-orphan-thread[data-status="resolved"] {
471    border-left-color: ~"rgba(var(--ann-resolved-rgb), 0.6)";
472}
473
474/* =========================================================================
475   Resolved annotation panels: shift to green accent
476   ========================================================================= */
477
478.ann-panel[data-status="resolved"] {
479    border-left-color: ~"rgba(var(--ann-resolved-rgb), 0.6)";
480}
481
482/* =========================================================================
483   Admin overview (annotated-pages table) — mirrors the lastseen panel
484   ========================================================================= */
485
486.plugin_annotations_admin .annotations_admin_bar {
487    margin: 0.6em 0;
488}
489
490.plugin_annotations_admin .annotations_admin_id {
491    color: __text_alt__;
492    font-size: 90%;
493}
494
495.plugin_annotations_admin td.annotations_admin_num,
496.plugin_annotations_admin td.annotations_admin_actions,
497.plugin_annotations_admin .annotations_admin_filteractions,
498.plugin_annotations_admin th {
499    text-align: center;
500    white-space: nowrap;
501}
502
503.plugin_annotations_admin th,
504.plugin_annotations_admin td {
505    vertical-align: middle;
506}
507
508/* per-column filter row */
509.plugin_annotations_admin .annotations_admin_filterrow td {
510    padding-top: 0.3em;
511    padding-bottom: 0.3em;
512}
513
514.plugin_annotations_admin .annotations_admin_filterrow input.edit {
515    width: 100%;
516    box-sizing: border-box;
517}
518
519.annotations_admin_clear {
520    margin-left: 0.5em;
521    font-size: 90%;
522}
523
524.annotations_admin_none {
525    text-align: center;
526    color: __text_alt__;
527    font-style: italic;
528}
529
530.annotations_admin_count {
531    color: __text_alt__;
532    font-size: 90%;
533}
534
535/* the POST forms targeted via the form= attribute carry only hidden inputs */
536.plugin_annotations_admin .annotations_admin_post {
537    display: none;
538}
539
540/* numbered pager */
541.annotations_admin_pager {
542    margin: 0.6em 0;
543}
544
545.annotations_admin_pager .pager_btn,
546.annotations_admin_pager .pager_cur,
547.annotations_admin_pager .pager_gap,
548.annotations_admin_pager .pager_disabled {
549    display: inline-block;
550    min-width: 1.6em;
551    padding: 0.15em 0.45em;
552    margin: 0 0.1em;
553    text-align: center;
554}
555
556.annotations_admin_pager .pager_btn,
557.annotations_admin_pager .pager_cur,
558.annotations_admin_pager .pager_disabled {
559    border: 1px solid __border__;
560}
561
562.annotations_admin_pager .pager_btn {
563    text-decoration: none;
564}
565
566.annotations_admin_pager .pager_cur {
567    background-color: __background_alt__;
568    font-weight: bold;
569}
570
571.annotations_admin_pager .pager_disabled {
572    color: __text_alt__;
573}
574
575.annotations_admin_pager .pager_gap {
576    border: 0;
577}
578