diff --git a/src/plainui/jinja2.py b/src/plainui/jinja2.py
index 7470c509f996be3834214c8a01e7fcad85c2ea9e..599c8300d469acc8779268a42a11b35947f7580b 100644
--- a/src/plainui/jinja2.py
+++ b/src/plainui/jinja2.py
@@ -4,6 +4,7 @@ from django.templatetags.static import static
 from django.urls import reverse
 from django.utils.formats import localize
 from django.utils.functional import LazyObject
+from django.utils.html import json_script
 from django.utils.timezone import localdate, localtime
 from django.utils.translation import ugettext, ungettext, get_language
 from django.contrib.humanize.templatetags.humanize import NaturalTimeFormatter
@@ -99,6 +100,7 @@ def environment(**options):
         'css_scope': css_scope,
         'get_language': get_language,
         'get_messages': get_messages,
+        'json_script': json_script,
         'num_of_unread_messages': num_of_unread_messages,
         'static': static,
         'url': url,
diff --git a/src/plainui/jinja2/plainui/base.html b/src/plainui/jinja2/plainui/base.html
index 883f9922dcdb98650639f8627806347175569c89..162b1da653c2d9bb148d5f4d2cf7b3cd2216589b 100644
--- a/src/plainui/jinja2/plainui/base.html
+++ b/src/plainui/jinja2/plainui/base.html
@@ -69,4 +69,5 @@
         </div>
     </body>
     {# <script async src="/static/plainui/js/tools.js" /></script> #}
+    <script async src="{{ static('plainui/js/modal.js') }}"></script>
 </html>
diff --git a/src/plainui/jinja2/plainui/components/calendar.html b/src/plainui/jinja2/plainui/components/calendar.html
index fbd7af6555b8d0eb6b7f1c2b4c4d87fbfe750b99..8210ae09adaa4b18fe23230f28153994f857e7eb 100644
--- a/src/plainui/jinja2/plainui/components/calendar.html
+++ b/src/plainui/jinja2/plainui/components/calendar.html
@@ -1,7 +1,7 @@
 {% macro h(minutes) -%}
 {{minutes*2}}px
 {%- endmacro %}
-{% macro calendar(events, my_favorite_events, my_scheduled_events, msg_none=_("No entries available.")) -%}
+{% macro calendar(events, my_favorite_events, my_scheduled_events, msg_none=_("No entries available."), public=False) -%}
 {% if not events -%}
     {{ msg_none }}
 {%- else -%}
@@ -24,7 +24,10 @@
                         <figure class="m-0 p-0 rc3-fahrplan__room-space" style="height: {{ h(entry.minutes) }}"></figure>
                     {% else %}
                     {% set color="primary" if entry.event.kind == "official" else "secondary" %}
-                        <a class="text-decoration-none" href="{{ url('plainui:event', conf_slug=conf.slug, event_slug=entry.event.slug) }}" title="{{entry.event.name}}">
+                        <a class="text-decoration-none" {% if public %}onclick="fahrplanModal('{{entry.event.id}}')" href="#"{% else %}href="{{ url('plainui:event', conf_slug=conf.slug, event_slug=entry.event.slug) }}"{% endif %} title="{{entry.event.name}}">
+                            {% if public %}
+                            {{ json_script({'title': entry.event.name, 'description': entry.event.description_html}, entry.event.id) }}
+                            {% endif %}
                             <figure class="p-1 my-0 mx-1 d-flex flex-column bg-{{color}} rc3-fahrplan__room-event" style="height: {{ h(entry.minutes) }}">
                                 <h2 class="mb-1 text-white rc3-fahrplan__event_title">{{entry.event.name}}
                                     {% if entry.event.language %}
diff --git a/src/plainui/jinja2/plainui/public_fahrplan.html b/src/plainui/jinja2/plainui/public_fahrplan.html
index ec539237ae473c75585def291bd91612c50d38c7..24f5d7bef13f346f581e9451f25d10d0bcfaaa29 100644
--- a/src/plainui/jinja2/plainui/public_fahrplan.html
+++ b/src/plainui/jinja2/plainui/public_fahrplan.html
@@ -10,6 +10,6 @@
     {% if mode == 'list' %}
         {{ list_events.list(events, [], []) }}
     {% elif mode == 'calendar' %}
-        {{ calendar(events, [], []) }}
+        {{ calendar(events, [], [], public=True) }}
     {% endif %}
 {% endblock %}
diff --git a/src/plainui/static/plainui/js/modal.js b/src/plainui/static/plainui/js/modal.js
new file mode 100644
index 0000000000000000000000000000000000000000..dcb2ca70d5cd7dfd3340a0560445b4c46be03e7d
--- /dev/null
+++ b/src/plainui/static/plainui/js/modal.js
@@ -0,0 +1,50 @@
+
+function showModal(title, content) {
+    let root = document.createElement('div');
+    root.innerHTML = `
+<div class="modal show" tabindex="-1" style="display:block;">
+    <div class="modal-dialog">
+      <div class="modal-content">
+        <div class="modal-header">
+          <h5 class="modal-title">${title}</h5>
+          <button type="button" class="close modal-close" data-dismiss="modal" aria-label="Close">
+            <span aria-hidden="true">&times;</span>
+          </button>
+        </div>
+        <div class="modal-body">
+          ${content}
+        </div>
+      </div>
+    </div>
+</div>
+`;
+    let modal_backdrop = document.createElement('div');
+    modal_backdrop.classList.add('modal-backdrop', 'show', 'modal-close')
+    document.body.appendChild(root);
+    document.body.appendChild(modal_backdrop);
+
+    let hide = function() {
+        console.log('hide_fn');
+        document.body.removeChild(root);
+        document.body.removeChild(modal_backdrop);
+    }
+
+//   let modal_backdrop = document.createElement('div');
+//   modal_backdrop.classList.add('modal-backdrop', 'modal-close');
+//   root.appendChild(modal_backdrop);
+
+  modal_backdrop.addEventListener('click', hide);
+  let close_elements = root.getElementsByClassName('modal-close');
+  for(let i = 0; i < close_elements.length; ++i) {
+      let el = close_elements[i];
+      el.addEventListener('click', hide)
+  }
+
+  document.body.appendChild(root);
+}
+
+function fahrplanModal(data_elem_id) {
+    let data_elem = document.getElementById(data_elem_id)
+    let data = JSON.parse(data_elem.innerText);
+    showModal(data.title, data.description);
+}
diff --git a/src/plainui/static/plainui/js/tools.js b/src/plainui/static/plainui/js/tools.js
index 38d09f3d7baa0319ea6199171d7ae6fb8c8077e1..5580500b19a3837b5580b90558fb43029ad9d51e 100644
--- a/src/plainui/static/plainui/js/tools.js
+++ b/src/plainui/static/plainui/js/tools.js
@@ -4,7 +4,7 @@ var docReady = (callback) => {
     else document.addEventListener("DOMContentLoaded", callback);
 }
 
-docReady(() => { 
+docReady(() => {
     // one click listener to rule them all :)
     document.addEventListener('click',function onclicked(e){
         documentClicked(e);
diff --git a/src/plainui/styles/_bootstrap.scss b/src/plainui/styles/_bootstrap.scss
index 48648eeeb306aa11759679bbe93ba8822459b147..46e5a433adab152dae3833fdb2997b2f4dee7fe3 100644
--- a/src/plainui/styles/_bootstrap.scss
+++ b/src/plainui/styles/_bootstrap.scss
@@ -36,9 +36,9 @@
  @import "bootstrap/scss/progress";
  @import "bootstrap/scss/media";
 //  @import "bootstrap/scss/list-group";
-//  @import "bootstrap/scss/close";
+ @import "bootstrap/scss/close";
 //  @import "bootstrap/scss/toasts";
-//  @import "bootstrap/scss/modal";
+ @import "bootstrap/scss/modal";
 //  @import "bootstrap/scss/tooltip";
 //  @import "bootstrap/scss/popover";
  @import "bootstrap/scss/carousel";
diff --git a/src/plainui/styles/utils/_bootstrap-theme-assembly.scss b/src/plainui/styles/utils/_bootstrap-theme-assembly.scss
index e020c53bb5cbdc7a331398aa9b3021cb78a573f3..87326e277c2232b389dba9ded30c2cdac72e69bf 100644
--- a/src/plainui/styles/utils/_bootstrap-theme-assembly.scss
+++ b/src/plainui/styles/utils/_bootstrap-theme-assembly.scss
@@ -62,3 +62,5 @@ $input-btn-focus-box-shadow: 0px 0px 3px 3px #FFFFFF, 0px 0px 2px 2px $tertiary,
 $btn-hover-text-shadow: 0px 0px 4px rgba(255, 255, 255, 0.75);
 $box-shadow-morphism: 2px 2px 4px #000000, -2px -2px 4px #162D38, inset 0px 0px 15px #0E1D24;
 $btn-active-box-shadow: $input-btn-focus-box-shadow;
+
+$modal-content-bg: $gray-900;
diff --git a/src/plainui/styles/utils/_bootstrap-theme-high-contrast.scss b/src/plainui/styles/utils/_bootstrap-theme-high-contrast.scss
index 36724b90e02e8f71fa743b0808124b9585230226..06a87017317dd7847eaf0822b20fce44a88614bc 100644
--- a/src/plainui/styles/utils/_bootstrap-theme-high-contrast.scss
+++ b/src/plainui/styles/utils/_bootstrap-theme-high-contrast.scss
@@ -59,3 +59,5 @@ $input-btn-focus-box-shadow: 0px 0px 3px 3px #BAF0FF, 0px 0px 2px 2px $tertiary,
 $btn-hover-text-shadow: 0px 0px 4px rgba(255, 255, 255, 0.75);
 $box-shadow-morphism: 2px 2px 4px #000000, -2px -2px 4px #1A1638, inset 2px 2px 8px $dark;
 $btn-active-box-shadow: $input-btn-focus-box-shadow;
+
+$modal-content-bg: $gray-900;
diff --git a/src/plainui/styles/utils/_bootstrap-theme-plattform.scss b/src/plainui/styles/utils/_bootstrap-theme-plattform.scss
index c23d459e867dd4f0bb15a36d0c250c1b87eee942..e6f291fab42b926ac6a4e17f9b24899a06399b33 100644
--- a/src/plainui/styles/utils/_bootstrap-theme-plattform.scss
+++ b/src/plainui/styles/utils/_bootstrap-theme-plattform.scss
@@ -63,3 +63,5 @@ $input-btn-focus-box-shadow: 0px 0px 3px 3px #BAF0FF, 0px 0px 2px 2px $tertiary,
 $btn-hover-text-shadow: 0px 0px 4px rgba(255, 255, 255, 0.75);
 $box-shadow-morphism: 2px 2px 4px #000000, -2px -2px 4px #1A1638;
 $btn-active-box-shadow: $input-btn-focus-box-shadow;
+
+$modal-content-bg: $gray-900;
diff --git a/src/plainui/styles/utils/_bootstrap-theme-world.scss b/src/plainui/styles/utils/_bootstrap-theme-world.scss
index 75f2bba70906f0dd3a82ef94507692225aa70557..11223724351fe3f776752d4bc69162e36e6dca8d 100644
--- a/src/plainui/styles/utils/_bootstrap-theme-world.scss
+++ b/src/plainui/styles/utils/_bootstrap-theme-world.scss
@@ -55,3 +55,5 @@ $input-btn-focus-box-shadow: 0px 0px 3px 3px #BAF0FF, 0px 0px 2px 2px $tertiary,
 $btn-hover-text-shadow: 0px 0px 4px rgba(255, 255, 255, 0.75);
 $box-shadow-morphism: 2px 2px 4px #000000, -2px -2px 4px #1A1638;
 $btn-active-box-shadow: $input-btn-focus-box-shadow;
+
+$modal-content-bg: $gray-900;
diff --git a/src/plainui/views.py b/src/plainui/views.py
index 5b97ccafa5aeaf169f464760452bc37f26915b11..35840b00211e0e0324e57828173b259b2698691c 100644
--- a/src/plainui/views.py
+++ b/src/plainui/views.py
@@ -24,7 +24,7 @@ from django.views.generic.edit import FormView, UpdateView
 from core import integrations
 from core.forms import PasswordResetForm
 from core.models import Assembly, AssemblyLikeCount, Badge, Conference, ConferenceMember, ConferenceMemberTicket, ConferenceTag, \
-        ConferenceTrack, DirectMessage, Event, EventLikeCount, EventParticipant, PlatformUser, Room, RoomLink, StaticPage, TagItem, UserBadge
+        ConferenceTrack, DirectMessage, Event, EventAttachment, EventLikeCount, EventParticipant, PlatformUser, Room, RoomLink, StaticPage, TagItem, UserBadge
 from core.models.ticket import TicketValidationError
 from core.search import search
 from core.utils import render_markdown
@@ -124,7 +124,7 @@ class EventView(ConferenceRequiredMixin, TemplateView):
         context = super().get_context_data(conf_slug=conf_slug, **kwargs)
         context['conf'] = self.conf
 
-        event = get_object_or_404(Event.objects.conference_accessible(self.conf), slug=event_slug)
+        event = get_object_or_404(Event.objects.conference_accessible(self.conf).select_related('assembly'), slug=event_slug)
         context['event'] = event
         favorites = _session_get_favorite_events(self.request.session, self.request.user)
         personal_calendar = _session_get_scheduled_events(self.request.session, self.request.user)
@@ -141,6 +141,11 @@ class EventView(ConferenceRequiredMixin, TemplateView):
         context['suggested'] = [
             s.event2 for s in event.suggestions.select_related('event2').exclude(event2=event.pk).exclude(event2__is_public=False).order_by('-like_ratio')[:5]
         ]
+
+        context['attachments'] = EventAttachment.objects.filter(
+            event=event,
+            visibility__in=[EventAttachment.Visibility.PUBLIC, EventAttachment.Visibility.CONFERENCE]
+        )
         context['scope'] = 'plattform' if event.kind == Event.Kind.OFFICIAL else 'assembly'
         return context