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