/* ============================================================
   Training Schedule — floating widget + modal calendar
   ------------------------------------------------------------
   Scoped under .ts-* so nothing here can reach the rest of the
   site. Matches the existing design language: APK Galeria, flat
   black on cream, square corners, thin 1px rules — the accent
   colours (--yellow / --red) come from :root in styles.css.
   ============================================================ */

.ts-launcher,
.ts-modal { font-family: "APK Galeria", sans-serif; }

/* ---------- floating launcher ----------
   Fixed to the right edge and vertically centred, so it stays in the
   middle of the viewport no matter how far the page has scrolled. */
.ts-launcher {
  position: fixed;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 60;                      /* above content, below the modal */
  display: block;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  color: #fff;
  text-align: left;
}
.ts-launcher-inner {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: 78px;
  padding: 20px 12px 22px;
  background: var(--black, #000);
  border: 1px solid var(--black, #000);
  border-right: none;
  transition: background .25s ease, transform .25s ease;
}
.ts-launcher:hover .ts-launcher-inner,
.ts-launcher:focus-visible .ts-launcher-inner {
  background: var(--red, #E2553C);
  transform: translateX(-4px);
}
.ts-launcher:focus-visible { outline: none; }
.ts-launcher:focus-visible .ts-launcher-inner {
  outline: 2px solid var(--black, #000);
  outline-offset: 3px;
}
.ts-launcher-icon { flex: none; }
.ts-launcher-text {
  font-size: 12px;
  font-weight: 600;
  line-height: 130%;
  letter-spacing: .04em;
  text-transform: uppercase;
  text-align: center;
}

/* count of upcoming trainings — a small yellow marker on the corner */
.ts-launcher-badge {
  position: absolute;
  top: -1px;
  left: -1px;
  min-width: 24px;
  padding: 3px 6px;
  background: var(--yellow, #EBC73A);
  color: var(--black, #000);
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  text-align: center;
}

/* hover hint that slides out from behind the tab */
.ts-launcher-tip {
  position: absolute;
  right: 100%;
  top: 50%;
  transform: translate(10px, -50%);
  margin-right: 8px;
  padding: 9px 14px;
  white-space: nowrap;
  background: var(--yellow, #EBC73A);
  color: var(--black, #000);
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
}
.ts-launcher:hover .ts-launcher-tip,
.ts-launcher:focus-visible .ts-launcher-tip {
  opacity: 1;
  transform: translate(0, -50%);
}

/* a gentle pulse the first few seconds, so the tab gets noticed once
   without becoming a permanently animated distraction */
@keyframes ts-nudge {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(-6px); }
}
.ts-launcher .ts-launcher-inner { animation: ts-nudge 2.4s ease-in-out 1.2s 3; }
.ts-launcher:hover .ts-launcher-inner { animation: none; }

/* ---------- modal shell ---------- */
.ts-modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.ts-modal[hidden] { display: none; }
.ts-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .55);
  animation: ts-fade .2s ease both;
}
@keyframes ts-fade { from { opacity: 0; } to { opacity: 1; } }

.ts-dialog {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 1000px;
  max-height: calc(100vh - 48px);
  background: var(--cream, #F3EFE4);
  border: 1px solid var(--black, #000);
  animation: ts-rise .24s cubic-bezier(.2, .7, .3, 1) both;
}
@keyframes ts-rise {
  from { opacity: 0; transform: translateY(14px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

.ts-dialog-head {
  flex: none;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  padding: 22px 24px 18px;
  background: #fff;
  border-bottom: 1px solid var(--black, #000);
}
.ts-eyebrow {
  margin: 0 0 4px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--red, #E2553C);
}
.ts-dialog-title {
  margin: 0;
  font-size: 30px;
  font-weight: 400;
  line-height: 115%;
  color: var(--black, #000);
}
.ts-close {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  background: #fff;
  color: var(--black, #000);
  border: 1px solid var(--black, #000);
  cursor: pointer;
  transition: background .18s ease, color .18s ease;
}
.ts-close:hover { background: var(--black, #000); color: #fff; }
.ts-close:focus-visible { outline: 2px solid var(--black, #000); outline-offset: 2px; }

/* calendar left, details right; the whole body scrolls on short screens */
.ts-body {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  min-height: 0;
  overflow: auto;
}

/* ---------- calendar ---------- */
.ts-cal {
  padding: 22px 24px 24px;
  border-right: 1px solid var(--black, #000);
  min-width: 0;
}
.ts-cal-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
}
.ts-month {
  flex: 1 1 auto;
  margin: 0;
  font-size: 20px;
  font-weight: 400;
  line-height: 1;
  color: var(--black, #000);
}
.ts-nav,
.ts-today {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #fff;
  color: var(--black, #000);
  border: 1px solid var(--black, #000);
  cursor: pointer;
  font-family: inherit;
  transition: background .18s ease, color .18s ease;
}
.ts-nav { width: 36px; height: 36px; padding: 0; }
.ts-today { height: 36px; padding: 0 14px; font-size: 13px; font-weight: 600; }
.ts-nav:hover, .ts-today:hover { background: var(--black, #000); color: #fff; }
.ts-nav:focus-visible,
.ts-today:focus-visible { outline: 2px solid var(--black, #000); outline-offset: 2px; }

/* weekday header + 7-column grid share the same track sizing */
.ts-dow,
.ts-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 6px;
}
.ts-dow {
  margin-bottom: 8px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, .55);
}
.ts-dow span { text-align: center; }

/* ---------- day cells ---------- */
.ts-day {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  aspect-ratio: 1 / 1;
  padding: 4px;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, .18);
  color: var(--black, #000);
  font-family: inherit;
  font-size: 15px;
  line-height: 1;
  cursor: default;
  transition: background .16s ease, border-color .16s ease, transform .16s ease;
}
/* leading / trailing blanks keep the grid rhythm without looking clickable */
.ts-day--pad { background: transparent; border-color: transparent; }

/* a date carrying at least one training: filled, bordered, obvious */
.ts-day--event {
  cursor: pointer;
  background: var(--yellow, #EBC73A);
  border-color: var(--black, #000);
  font-weight: 600;
}
.ts-day--event:hover {
  transform: translateY(-2px);
  background: var(--black, #000);
  color: #fff;
}
.ts-day--event:focus-visible {
  outline: 2px solid var(--black, #000);
  outline-offset: 2px;
}
/* middle / end of a multi-day span: same fill, squared against its
   neighbour so the run reads as one continuous bar */
.ts-day--span-mid { border-left-color: transparent; border-right-color: transparent; }
.ts-day--span-start { border-right-color: transparent; }
.ts-day--span-end { border-left-color: transparent; }

/* today: a thick left rule, distinct from the event fill so a day can be
   both today and a training day without the two cues colliding */
.ts-day--today { box-shadow: inset 3px 0 0 var(--red, #E2553C); }
.ts-day--past:not(.ts-day--event) { color: rgba(0, 0, 0, .35); }

.ts-day-num { pointer-events: none; }

/* one dot per training on that date, capped by the markup at 3 */
.ts-day-dots {
  display: flex;
  gap: 3px;
  height: 5px;
  pointer-events: none;
}
.ts-day-dots i {
  width: 5px;
  height: 5px;
  background: var(--black, #000);
  border-radius: 50%;
}
.ts-day--event:hover .ts-day-dots i { background: #fff; }

/* the selected date stays visibly chosen while its details are shown */
.ts-day--selected {
  background: var(--black, #000);
  color: #fff;
  border-color: var(--black, #000);
}
.ts-day--selected .ts-day-dots i { background: var(--yellow, #EBC73A); }

.ts-legend {
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
  margin: 16px 0 0;
  font-size: 12px;
  color: rgba(0, 0, 0, .6);
}
.ts-legend-item { display: inline-flex; align-items: center; gap: 7px; }
.ts-dot { width: 10px; height: 10px; flex: none; border: 1px solid var(--black, #000); }
.ts-dot--event { background: var(--yellow, #EBC73A); }
.ts-dot--today { background: var(--red, #E2553C); border-color: var(--red, #E2553C); }

/* grid states while loading / on error */
.ts-grid.is-loading { opacity: .4; transition: opacity .12s ease; }
.ts-grid-msg {
  grid-column: 1 / -1;
  padding: 28px 0;
  text-align: center;
  font-size: 14px;
  color: rgba(0, 0, 0, .6);
}

/* ---------- details pane ---------- */
.ts-detail {
  padding: 22px 22px 24px;
  background: var(--cream, #F3EFE4);
  min-width: 0;
}

/* placeholder shown until a date is picked */
.ts-detail-empty { color: var(--black, #000); }

/* ---------- the placeholder's heading row ----------
   The icon and the heading share one line. Stacked, the calendar graphic took a
   row of its own and pushed "Pick a highlighted date" down against the sentence
   under it, so the icon read as the heading and the heading as body copy — and
   the instruction, which is the whole point of this pane, was the third thing
   the eye reached. Beside the icon it is read with it, as one line.

   align-items: center keeps the pair on a shared centreline; the title is free
   to wrap on a narrow pane without dragging the icon off it. */
.ts-detail-empty-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
}
.ts-detail-empty-icon {
  flex: none;                            /* never squeezed if the title wraps */
  /* Sized to the heading it now sits beside rather than as a graphic standing on
     its own. The viewBox scales, so the 34 in the markup is only the fallback
     for a page that somehow loads without this stylesheet. */
  width: 26px;
  height: 26px;
  color: rgba(0, 0, 0, .35);
}
.ts-detail-empty-title {
  margin: 0;                             /* the row above carries the spacing */
  font-size: 17px;
  font-weight: 600;
}
/* The office, named after the instruction by calendar.js. A step lighter than
   the heading it follows so the two read as one line with a qualifier on it
   rather than as two competing headings; size and colour are inherited. No
   display is set here, so the hidden attribute still takes it out of the line
   on the every-branch feed, where there is no one office to name. */
.ts-detail-empty-branch { font-weight: 500; }
.ts-detail-empty-text {
  margin: 0;
  font-size: 14px;
  line-height: 150%;
  color: rgba(0, 0, 0, .7);
}

/* This month's trainings, listed so the pane says what is in the month without
   a date having to be clicked. Server-rendered for the first paint, then rebuilt
   by calendar.js from each month's payload. A month with nothing in it hides
   this along with the rest of .ts-detail-empty and shows .ts-blank instead — it
   never falls back to another month's dates. */
.ts-upnext { margin-top: 22px; border-top: 1px solid rgba(0, 0, 0, .2); padding-top: 16px; }
.ts-upnext-label {
  margin: 0 0 10px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, .55);
}
.ts-upnext-item {
  display: block;
  width: 100%;
  margin-bottom: 8px;
  padding: 10px 12px;
  text-align: left;
  background: #fff;
  border: 1px solid var(--black, #000);
  color: var(--black, #000);
  font-family: inherit;
  cursor: pointer;
  transition: background .16s ease, color .16s ease;
}
.ts-upnext-item:hover { background: var(--black, #000); color: #fff; }
.ts-upnext-item:focus-visible { outline: 2px solid var(--black, #000); outline-offset: 2px; }
.ts-upnext-date {
  display: block;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--red, #E2553C);
}
.ts-upnext-item:hover .ts-upnext-date { color: var(--yellow, #EBC73A); }
.ts-upnext-title { display: block; margin-top: 3px; font-size: 14px; line-height: 135%; }

/* Registration state on the row itself, so "can I still sign up for this?" is
   answered in the list rather than only after a date is clicked. Same pill as
   the event cards (.ts-event-status, and every state colour with it), one size
   down: it sits inline at the end of the title, and at the card's size it would
   grow the row's line box and cost the pane height the preview is budgeted on.

   Inline rather than a line of its own for the same reason — MONTH_PREVIEW rows
   plus the "View all" button are sized to sit beside the calendar, and a second
   line per row would spend that budget on whitespace. At 10px/1.2 the pill is
   16px tall against the title's 18.9px line box, so it costs the row nothing.

   Qualified by .ts-upnext-item, not left as a bare class: .ts-event-status is
   declared further down this file, so at equal specificity its own font-size and
   padding would win on document order and the pill would come out card-sized.
   The extra class also scopes this to rows — the dialog's rows are the same
   .ts-upnext-item buttons, so it reaches those too. */
.ts-upnext-item .ts-upnext-status {
  padding: 1px 6px;
  gap: 4px;
  font-size: 10px;
  line-height: 1.2;
  /* Centred on the text rather than sat on its baseline. The pill is a flex
     container whose first item is the dot, so its own baseline is the dot's
     bottom edge — aligning to that would hang the pill low. `middle` ignores
     the pill's baseline and centres it on the title's x-height instead. */
  vertical-align: middle;
  /* fades with the row's own background so the border below moves with it
     rather than snapping ahead */
  transition: border-color .16s ease;
}
.ts-upnext-item .ts-upnext-status::before { width: 5px; height: 5px; }
/* Hovered, the row turns solid black, which the black "Closed" pill and its
   black border would sink into. A white edge keeps every state legible as a chip
   on the inverted row — the fills already read against black. */
.ts-upnext-item:hover .ts-upnext-status { border-color: #fff; }
/* No height cap and no scrollbar. The list used to cap itself at ~306px and
   scroll, which put a scroll container inside a pane that already sits beside a
   calendar — on a month with twenty trainings most of the month was hidden
   behind it with nothing to say so. The pane now lists a fixed preview
   (MONTH_PREVIEW in calendar.js) and the rest is read in the dialog below, so
   the pane's height is bounded by a count instead of by an overflow. */
.ts-upnext-list { min-width: 0; }

/* "View all 23 trainings" — the way out of the preview, rendered only when the
   month holds more than the preview shows. Full width under the list so it
   reads as the end of it, and the same square, black-bordered, inverting shape
   as .ts-upnext-item, one step quieter (no fill until hovered).

   The preview's last row keeps its 8px bottom margin, which is the gap between
   the two, so this only needs a hair of its own.

   [hidden] is spelled out because the display below would otherwise beat the
   UA stylesheet's [hidden] { display: none } and the button would stay
   visible on a month that does not need it. */
.ts-upnext-more {
  display: block;
  width: 100%;
  padding: 10px 12px;
  background: transparent;
  border: 1px solid var(--black, #000);
  color: var(--black, #000);
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .04em;
  cursor: pointer;
  transition: background .16s ease, color .16s ease;
}
.ts-upnext-more[hidden] { display: none; }
.ts-upnext-more:hover { background: var(--black, #000); color: #fff; }
.ts-upnext-more:focus-visible { outline: 2px solid var(--black, #000); outline-offset: 2px; }

/* ---------- "all trainings" dialog ----------
   Where a month longer than the preview is read in full. Built by calendar.js
   on the first open and appended to <body>, so the many months that never need
   it pay nothing for it.

   Deliberately its own .ts-all-* shell rather than a reuse of .ts-modal: the
   floating widget owns those classes and may be on the same page. The shape is
   the one already established there — fixed overlay, tinted backdrop, bordered
   dialog, the shared ts-fade / ts-rise keyframes — and everything inside is the
   pane's own furniture (.ts-eyebrow, .ts-close, .ts-upnext-item), so the list
   looks identical in both places.

   Content arrives in batches on request, so the first view is short whether the
   month holds twelve trainings or sixty; the body's overflow is only the safety
   net for a batch taller than the viewport. */
.ts-all {
  position: fixed;
  inset: 0;
  /* above the launcher (60) and the widget's own modal (100), below the
     recordings lightbox (120) — see the z-index note in styles.css */
  z-index: 110;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  font-family: "APK Galeria", sans-serif;
}
.ts-all[hidden] { display: none; }
.ts-all-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .55);
  animation: ts-fade .2s ease both;
}
.ts-all-dialog {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  /* one column of cards: the list is the whole content, so a wider dialog would
     only stretch each row */
  max-width: 560px;
  max-height: calc(100vh - 48px);
  background: var(--cream, #F3EFE4);
  border: 1px solid var(--black, #000);
  animation: ts-rise .24s cubic-bezier(.2, .7, .3, 1) both;
}
.ts-all-head {
  flex: none;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  padding: 20px 22px 16px;
  background: #fff;
  border-bottom: 1px solid var(--black, #000);
}
.ts-all-title {
  margin: 0;
  font-size: 22px;
  font-weight: 400;
  line-height: 118%;
  color: var(--black, #000);
}
.ts-all-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 18px 22px;
}
/* the rows carry a bottom margin for the gaps between them; the last one would
   otherwise leave a stray gap at the end of the scroll area */
.ts-all-list .ts-upnext-item:last-child { margin-bottom: 0; }
/* the count and the next batch, held together on a bar that stays put while the
   list above it grows */
.ts-all-foot {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px 22px 16px;
  background: #fff;
  border-top: 1px solid var(--black, #000);
}
.ts-all-count { margin: 0; font-size: 12px; color: rgba(0, 0, 0, .65); }
.ts-all-more {
  flex: none;
  display: inline-flex;
  align-items: center;
  padding: 10px 16px;
  background: var(--black, #000);
  border: 1px solid var(--black, #000);
  color: #fff;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background .18s ease, color .18s ease;
}
/* spelled out for the same reason as .ts-upnext-more[hidden] above */
.ts-all-more[hidden] { display: none; }
.ts-all-more:hover { background: #fff; color: var(--black, #000); }
.ts-all-more:focus-visible { outline: 2px solid var(--black, #000); outline-offset: 2px; }

/* full screen on a phone, the same trade the widget's modal makes */
@media (max-width: 640px) {
  .ts-all { padding: 0; }
  .ts-all-dialog { max-width: none; max-height: 100vh; height: 100%; border: none; }
  .ts-all-head { padding: 16px 16px 14px; }
  .ts-all-title { font-size: 19px; }
  .ts-all-body { padding: 16px; }
  /* the count takes its own row above the button, which then spans the width —
     side by side at this size the count would wrap to three cramped lines */
  .ts-all-foot { flex-wrap: wrap; gap: 10px; padding: 12px 16px 14px; }
  .ts-all-count { flex: 1 1 100%; }
  .ts-all-more { flex: 1 1 auto; justify-content: center; }
}

/* the selected date's heading + one card per training */
/* holds the heading and every card for the picked date; scrolls on its own
   so a date with many trainings never stretches the dialog */
.ts-detail-list {
  min-width: 0;
  max-height: 100%;
  overflow-y: auto;
}
/* heading row: date on the left, the details Close button hard right */
.ts-detail-head {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(0, 0, 0, .2);
  /* the list scrolls on its own, so the heading sticks to the top — the
     Close button stays reachable however far down the cards you are */
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--cream, #F3EFE4);
}
.ts-detail-head .ts-detail-date {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  padding-bottom: 0;
  border-bottom: none;
}
/* closes the selected date and returns to the "Coming up next" placeholder */
.ts-detail-close {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  background: #fff;
  color: var(--black, #000);
  border: 1px solid var(--black, #000);
  cursor: pointer;
  transition: background .18s ease, color .18s ease;
}
.ts-detail-close:hover { background: var(--black, #000); color: #fff; }
.ts-detail-close:focus-visible { outline: 2px solid var(--black, #000); outline-offset: 2px; }

.ts-detail-date {
  margin: 0 0 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(0, 0, 0, .2);
  font-size: 18px;
  font-weight: 600;
  color: var(--black, #000);
}
.ts-detail-count {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  font-weight: 400;
  color: rgba(0, 0, 0, .6);
}
.ts-event {
  margin-bottom: 14px;
  padding: 14px;
  background: #fff;
  border: 1px solid var(--black, #000);
}
.ts-event:last-child { margin-bottom: 0; }
.ts-event-title {
  margin: 0 0 8px;
  font-size: 16px;
  font-weight: 600;
  line-height: 130%;
  color: var(--black, #000);
}
/* "3 days" flag on multi-day trainings */
.ts-event-tag {
  display: inline-block;
  padding: 3px 8px;
  background: var(--yellow, #EBC73A);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--black, #000);
}
/* the flags sit on one wrapping row above the title */
.ts-event-flags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
}

/* ---------- registration status ----------
   One pill per state. The palette carries the meaning: green for open,
   solid black for closed, red for cancelled, yellow for postponed. The
   text label is always present, so colour is never the only signal. */
.ts-event-status {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 8px;
  border: 1px solid var(--black, #000);
  background: #fff;
  color: var(--black, #000);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  white-space: nowrap;
}
.ts-event-status::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: none;
  background: currentColor;
}
.ts-event-status--open      { background: #E7F3E9; }
.ts-event-status--closed    { background: var(--black, #000);  color: #fff; }
.ts-event-status--cancelled { background: var(--red, #E2553C); color: #fff; border-color: var(--red, #E2553C); }
.ts-event-status--postponed { background: var(--yellow, #EBC73A); }

/* shown in place of the Register button once registration is not open */
.ts-event-closed {
  margin: 12px 0 0;
  padding: 9px 12px;
  background: var(--cream, #F3EFE4);
  border-left: 3px solid var(--black, #000);
  font-size: 12.5px;
  line-height: 145%;
  color: rgba(0, 0, 0, .75);
}
/* ---------- detail rows: icon badge + label + value ----------
   Each row is a 2-column grid so a value that wraps stays aligned under
   itself instead of running back under the icon. The badge colour is set
   per field, which lets the eye find "When" or "Where" without reading. */
.ts-event-meta {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  align-items: start;
  gap: 9px;
  margin: 0 0 8px;
  font-size: 13px;
  line-height: 140%;
  color: rgba(0, 0, 0, .75);
}
.ts-event-meta:last-child { margin-bottom: 0; }

.ts-event-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: 1px solid var(--black, #000);
  /* the icon inherits currentColor, so one colour per row is enough */
  background: var(--ts-ico-bg, #fff);
  color: var(--ts-ico-fg, #000);
}
.ts-event-ico svg { display: block; }

/* per-field accents, drawn from the site palette */
.ts-event-meta--when  { --ts-ico-bg: var(--red, #E2553C);    --ts-ico-fg: #fff; }
.ts-event-meta--time  { --ts-ico-bg: var(--yellow, #EBC73A); --ts-ico-fg: #000; }
.ts-event-meta--where { --ts-ico-bg: var(--black, #000);     --ts-ico-fg: #fff; }
.ts-event-meta--desc  { --ts-ico-bg: #fff;                   --ts-ico-fg: #000; }

.ts-event-meta-body { min-width: 0; }
.ts-event-meta-label {
  display: block;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, .55);
}
.ts-event-meta-value {
  display: block;
  margin-top: 1px;
  font-size: 13px;
  color: var(--black, #000);
  overflow-wrap: break-word;           /* a long location cannot overflow */
}
/* the description keeps the line breaks the admin typed */
.ts-event-meta--desc .ts-event-meta-value {
  white-space: pre-line;
  line-height: 155%;
  color: rgba(0, 0, 0, .8);
}
.ts-event-register {
  display: inline-block;
  margin-top: 12px;
  padding: 10px 16px;
  background: var(--red, #E2553C);
  color: #fff;
  border: 1px solid var(--red, #E2553C);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  transition: background .18s ease, color .18s ease;
}
.ts-event-register:hover {
  background: var(--black, #000);
  border-color: var(--black, #000);
  color: #fff;
}
.ts-event-register:focus-visible { outline: 2px solid var(--black, #000); outline-offset: 2px; }

/* ---------- native (in-page) calendar ----------
   Inline mode reuses .ts-dialog for the card, so the calendar keeps the same
   borders, head bar and two-column split it has in the modal. What changes is
   what a page section needs: normal flow, no backdrop, no entry animation, no
   viewport-capped height — and a compact grid, since a full-width square-cell
   calendar would run past the fold and force the visitor to scroll. */
.ts-inline {
  font-family: "APK Galeria", sans-serif;
  background: var(--cream, #F3EFE4);
  padding: 80px 0 72px;
}

/* section heading above the card */
.ts-inline-title {
  max-width: 1180px;
  margin: 0 auto 28px;
  color: var(--black, #000);
  font-family: "APK Galeria";
  font-size: 31px;
  font-style: normal;
  font-weight: 400;
  line-height: 120%;
  text-align: left;
}

.ts-inline .ts-dialog {
  max-width: 1180px;             /* --max-split, matching the other sections */
  margin: 0 auto;
  max-height: none;              /* grows with its content instead of scrolling */
  animation: none;
  /* a soft drop shadow lifts the card off the cream page; the modal got this
     separation from its backdrop instead */
  box-shadow: 0 1px 0 rgba(0, 0, 0, .06), 0 18px 40px -28px rgba(0, 0, 0, .45);
}
/* the head reads as a title bar across the top of the card */
.ts-inline .ts-dialog-head { padding: 20px 28px 18px; }
.ts-inline .ts-eyebrow { letter-spacing: .12em; }
.ts-inline .ts-dialog-title { font-size: 22px; }

/* quieter chrome in page context: the modal needed hard black edges to hold
   itself together over a backdrop, whereas in the page the outer border does
   that job and the inner rules can be lighter. The details pane keeps hard
   black edges — see the terracotta block below. */
.ts-inline .ts-dialog-head { border-bottom-color: rgba(0, 0, 0, .12); }
/* empty cells were already invisible; the rest get a hairline */
.ts-inline .ts-day:not(.ts-day--event):not(.ts-day--pad) {
  border-color: rgba(0, 0, 0, .1);
}

/* One clear card on the cream page, with a full-strength terracotta side.
   The details pane inherited cream from the modal, where a dark backdrop kept
   it contained — in the page that cream is the same #F3EFE4 as the section
   behind it, so the card's right half dissolved. It now carries solid
   --terracotta #E2725B: black text on it measures 6.8:1, so every label in the
   pane clears WCAG AA. White text would only reach 3.1:1, which is why
   everything on the terracotta stays black and the content cards stay white. */
.ts-inline {
  --ts-terra: var(--terracotta, #E2725B);
  --ts-terra-line: rgba(0, 0, 0, .22);   /* hairline that reads on terracotta */
}
/* the dialog was cream; white lets the terracotta edge stay crisp */
.ts-inline .ts-dialog { background: #fff; }
.ts-inline .ts-cal { background: #fff; }
.ts-inline .ts-detail { background: var(--ts-terra); }
/* the sticky heading scrolls over the colour, so it must match it */
.ts-inline .ts-detail-head { background: var(--ts-terra); }
/* the split is now tonal, so the divider only needs to be a seam */
.ts-inline .ts-cal { border-right-color: var(--black, #000); }

/* white cards float on the colour: page (cream) → card (white | terracotta)
   → content (white). The white is what the eye reads; the terracotta frames it. */
.ts-inline .ts-event,
.ts-inline .ts-upnext-item {
  background: #fff;
  border-color: var(--black, #000);
}
.ts-inline .ts-upnext-item:hover { background: var(--black, #000); color: #fff; }
/* the closed-registration note sits inside a white card, so it keeps cream */
.ts-inline .ts-event-closed { background: var(--cream, #F3EFE4); }

/* Text sitting directly on the terracotta. The muted greys were tuned for
   cream and go flat on a saturated ground, so each one is darkened until it
   holds its own — the hierarchy is kept by weight and size instead of alpha. */
.ts-inline .ts-detail-empty-icon { color: rgba(0, 0, 0, .55); }
.ts-inline .ts-detail-empty-text { color: rgba(0, 0, 0, .85); }
.ts-inline .ts-upnext-label { color: rgba(0, 0, 0, .7); }
.ts-inline .ts-detail-count { color: rgba(0, 0, 0, .7); }
/* dividers on the terracotta */
.ts-inline .ts-detail-head,
.ts-inline .ts-detail-date { border-bottom-color: var(--ts-terra-line); }
.ts-inline .ts-upnext { border-top-color: var(--ts-terra-line); }
/* NB .ts-upnext-date stays --red #E2553C: it sits on the white card, not on
   the terracotta, so it still has the contrast it needs. */

/* the cells no longer need their own fill against a white pane. No hover cue
   here — only event days are clickable, and they keep their own. */
.ts-inline .ts-day:not(.ts-day--event):not(.ts-day--selected) { background: transparent; }
/* the body scrolled inside the dialog; in the page it should not */
.ts-inline .ts-body { overflow: visible; }
/* likewise the details list: let the column grow rather than scroll */
.ts-inline .ts-detail-list { max-height: none; overflow-y: visible; }
/* nothing sticks in page flow — the heading would follow the window otherwise */
.ts-inline .ts-detail-head { position: static; }

/* a touch more room for the details column, so event cards read comfortably
   while the calendar itself gets no wider than it needs to be. The calendar
   column is sized to the compact grid below (430px + 28px padding each side)
   and the details pane takes whatever is left. */
.ts-inline .ts-body { grid-template-columns: 486px minmax(0, 1fr); }
.ts-inline .ts-cal,
.ts-inline .ts-detail { padding: 26px 28px 28px; }

/* Compact grid. The cells are squares (aspect-ratio is inherited untouched),
   so the only way to shorten the calendar is to narrow it: at 430px a cell is
   ~57px and six rows come to ~368px, which keeps the whole card on one screen
   instead of forcing a scroll. */
.ts-inline .ts-dow,
.ts-inline .ts-grid {
  max-width: 430px;
  gap: 5px;
}
.ts-inline .ts-cal-bar { max-width: 430px; margin-bottom: 16px; }
.ts-inline .ts-legend { max-width: 430px; margin-top: 18px; }
.ts-inline .ts-month { font-size: 18px; }
.ts-inline .ts-nav { width: 32px; height: 32px; }
.ts-inline .ts-today { height: 32px; padding: 0 12px; font-size: 12px; }
.ts-inline .ts-day { font-size: 14px; gap: 4px; }
/* the number carries the date; the dots sit just under it */
.ts-inline .ts-day-dots { height: 4px; gap: 3px; }
.ts-inline .ts-day-dots i { width: 4px; height: 4px; }

/* ---------- branch picker ----------
   Above the month bar, because the branch is asked before the month: the
   schedule is read one office at a time, and until a chip is pressed the
   calendar has nothing to list.

   Chips rather than a <select>: three fixed options fit on one line, so the
   whole choice is readable at a glance and one press wide. The pressed one is
   filled black — the same inversion .ts-nav and .ts-today make on hover, so the
   card gains no new visual language — and aria-pressed carries the same state
   to assistive tech.

   Inline only in practice: the floating widget has no picker and asks the feed
   for every branch, exactly as it did before branches existed. */
.ts-branches {
  max-width: 430px;
  margin-bottom: 16px;
}
.ts-branches-label {
  margin: 0 0 8px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, .55);
}
.ts-branch-chips { display: flex; flex-wrap: wrap; gap: 8px; }

.ts-branch {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;                              /* marker, then the office */
  height: 32px;
  padding: 0 12px;
  background: #fff;
  color: var(--black, #000);
  border: 1px solid var(--black, #000);
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  transition: background .18s ease, color .18s ease;
}
.ts-branch:hover { background: var(--black, #000); color: #fff; }
.ts-branch:focus-visible { outline: 2px solid var(--black, #000); outline-offset: 2px; }
/* the chosen branch: filled, and it stays filled on hover so the pressed state
   is never mistaken for a hover that has not landed yet */
.ts-branch[aria-pressed="true"] {
  background: var(--black, #000);
  color: #fff;
  cursor: default;
}

/* ---------- each office's marker ----------
   Without one the three chips are white boxes with black text sitting directly
   above .ts-nav and .ts-today — white boxes with black text — so the first
   thing the page asks for looked like part of the month paging and was read
   straight past. A filled marker gives the row a colour of its own, and the
   pin is the same one the "Where" detail row draws, which ties the choice to
   the place it picks.

   The accents are the three already used by the detail rows
   (.ts-event-meta--when / --time / --where), so this adds a marker, not a new
   palette. Colour is never the only signal: the office is written beside it,
   and which one is on is still carried by aria-pressed and the filled chip.

   A fourth office added to acr_training_branches() needs no change here — with
   no accent of its own it falls back to the outlined white badge, so it still
   gets the pin. */
.ts-branch-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 20px;
  height: 20px;
  border: 1px solid var(--black, #000);
  background: var(--ts-branch-bg, #fff);
  /* the pin inherits currentColor, so one pair per office is enough */
  color: var(--ts-branch-fg, #000);
  /* clicks land on the chip itself, never on the badge or its <path>, which is
     what the delegated handler in calendar.js closest()es from */
  pointer-events: none;
  transition: border-color .18s ease;
}
.ts-branch-ico svg { display: block; }

.ts-branch[data-ts-branch="manila"] { --ts-branch-bg: var(--red, #E2553C);    --ts-branch-fg: #fff; }
.ts-branch[data-ts-branch="cebu"]   { --ts-branch-bg: var(--yellow, #EBC73A); --ts-branch-fg: #000; }
.ts-branch[data-ts-branch="davao"]  { --ts-branch-bg: var(--black, #000);     --ts-branch-fg: #fff; }

/* Filled chip — hovered, or the one that is on: the badge's black border would
   sink into the black fill, so it takes a white edge, the same way
   .ts-upnext-status does on an inverted row. Davao's accent is that same
   black, so its badge reads there as the pin in a white outline; the fill
   behind it changes, the office keeps its mark. */
.ts-branch:hover .ts-branch-ico,
.ts-branch[aria-pressed="true"] .ts-branch-ico { border-color: #fff; }

/* ---------- empty details pane ("being prepared" / "which branch") ----------
   .is-blank is put on .ts-inline whenever the pane has nothing to list: no
   branch chosen yet (how the page opens, set server-side), a branch with nothing
   published, or a branch that is simply quiet this month. calendar.js keeps it
   in step as chips and months are pressed.

   The calendar itself stays: the branch picker, the month bar, the weekday
   header, the grid and the legend all still work, so a visitor can pick an
   office and page through months. Only the details pane changes — its "Pick a
   highlighted date" placeholder and its month list have nothing of this branch's
   month to show, and another month's or another branch's dates in their place
   would read as this one's, so .ts-blank takes that spot and explains the
   situation instead.

   Nothing here is scoped to .is-blank only in CSS — .ts-blank is display:none
   by default, so a pane with trainings never renders or animates any of it. */
.ts-blank { display: none; }

/* the placeholder and the month list have nothing to point at */
.ts-inline.is-blank .ts-detail-empty { display: none; }

.ts-inline.is-blank .ts-blank {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  /* capped and centred: the pane is comfortable at two columns but goes
     full-width once the layout stacks, where an unbounded panel would sprawl */
  max-width: 420px;
  margin: 0 auto;
  padding: 6px 0 4px;
  /* the panel itself eases in, so the switch is not a hard cut */
  animation: ts-blank-in .5s cubic-bezier(.2, .7, .3, 1) both;
}
@keyframes ts-blank-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ---- the animation ----
   A calendar sheet with one date still pulsing, and a clock pinned to its
   corner whose hands keep turning. Two slow, unhurried loops rather than a
   spinner: the point is "a date is being set", not "wait".

   Every corner is square — the card, the grid cells and the buttons on this
   page have no radii, so the graphic does not introduce any. */
.ts-blank-anim {
  position: relative;
  width: 88px;
  height: 88px;
  margin-bottom: 22px;
  /* currentColor drives the sheet outline, the head bar and the hour hand */
  color: var(--black, #000);
}

.ts-blank-cal { display: block; width: 100%; height: 100%; }

/* the one date still being decided keeps breathing */
.ts-blank-cal-dot {
  fill: var(--red, #E2553C);
  transform-box: fill-box;
  transform-origin: center;
  animation: ts-blank-dot 2.4s ease-in-out infinite;
}
@keyframes ts-blank-dot {
  0%, 100% { opacity: .35; transform: scale(.85); }
  50%      { opacity: 1;   transform: scale(1.15); }
}

/* the clock sits over the sheet's bottom-right corner, on its own white chip
   so it stays legible against the terracotta pane behind it */
.ts-blank-clock {
  position: absolute;
  right: -6px;
  bottom: -6px;
  display: block;
  width: 34px;
  height: 34px;
  background: #fff;
  border: 1px solid var(--black, #000);
}
.ts-blank-clock svg { display: block; width: 100%; height: 100%; }

/* Different periods, so the pair never re-syncs into a single sweep. The
   minute hand carries the accent; the hour hand is black and barely moves. */
.ts-blank-hand {
  stroke-width: 2;
  transform-origin: 17px 17px;
  stroke-linecap: butt;          /* squared ends, like everything else here */
}
.ts-blank-hand--hour { stroke: currentColor;         animation: ts-blank-turn 24s linear infinite; }
.ts-blank-hand--min  { stroke: var(--red, #E2553C);  animation: ts-blank-turn 8s linear infinite; }
@keyframes ts-blank-turn {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* ---- the message ----
   Sized for the details pane, so a step down from the page's headings: the
   calendar beside it stays the main object on the card. */
.ts-blank-title {
  margin: 0 0 10px;
  color: var(--black, #000);
  font-size: 18px;
  font-weight: 600;
  line-height: 135%;
}
.ts-blank-text {
  margin: 0;
  max-width: 32ch;
  font-size: 14px;
  line-height: 160%;
  /* the pane is terracotta, where a muted grey goes flat — same darkening the
     other text on this side gets (see .ts-inline .ts-detail-empty-text) */
  color: rgba(0, 0, 0, .85);
}

/* ---- the rows being filled in ----
   Three bars of falling width with a highlight sweeping across them, one after
   the next: the schedule literally being written out. Sits between the message
   and the CTA, where the first few dates would eventually appear. */
.ts-blank-rows {
  display: flex;
  flex-direction: column;
  align-self: stretch;
  gap: 10px;
  margin-top: 26px;
}
.ts-blank-row {
  position: relative;
  height: 12px;
  /* a wash of the pane colour: present, but clearly not content yet */
  background: rgba(255, 255, 255, .45);
  overflow: hidden;
}
.ts-blank-row:nth-child(1) { width: 100%; }
.ts-blank-row:nth-child(2) { width: 78%; }
.ts-blank-row:nth-child(3) { width: 56%; }

.ts-blank-row::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .85), transparent);
  animation: ts-blank-sweep 2.2s ease-in-out infinite;
}
/* staggered, so the sweep reads as one pass down the list */
.ts-blank-row:nth-child(2)::after { animation-delay: .25s; }
.ts-blank-row:nth-child(3)::after { animation-delay: .5s; }

@keyframes ts-blank-sweep {
  0%        { transform: translateX(-100%); }
  60%, 100% { transform: translateX(100%); }
}

.ts-blank-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  /* fills the pane's width: the only action on this side, so it reads as the
     next step rather than a stray link */
  align-self: stretch;
  margin-top: 26px;
  padding: 12px 18px;
  background: var(--black, #000);
  border: 1px solid var(--black, #000);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  transition: background .18s ease, color .18s ease;
}
/* inverts to white on hover, the same swap .ts-upnext-item makes in reverse —
   --red would sit too close to the terracotta behind it to register */
.ts-blank-cta:hover {
  background: #fff;
  border-color: var(--black, #000);
  color: var(--black, #000);
}
.ts-blank-cta:focus-visible { outline: 2px solid var(--black, #000); outline-offset: 2px; }
.ts-blank-cta svg { flex: none; transition: transform .18s ease; }
.ts-blank-cta:hover svg { transform: translateX(3px); }
/* Spelled out for the same reason as .ts-upnext-more[hidden] above: the
   display rule here would otherwise beat the UA stylesheet's
   [hidden] { display: none } and the link would stay on screen. calendar.js
   hides it while the panel is still asking which branch — there is nothing to
   leave the page for until a branch has been read and come back empty. */
.ts-blank-cta[hidden] { display: none; }

@media (max-width: 1100px) {
  /* narrower calendar column so the details pane keeps a usable width */
  .ts-inline .ts-body { grid-template-columns: 446px minmax(0, 1fr); }
  .ts-inline .ts-dow,
  .ts-inline .ts-grid,
  .ts-inline .ts-cal-bar,
  .ts-inline .ts-branches,
  .ts-inline .ts-legend { max-width: 390px; }
}

@media (max-width: 900px) {
  .ts-inline { padding: 56px 0 48px; }
  .ts-inline-title { font-size: 27px; margin-bottom: 22px; }
  .ts-inline .ts-body { grid-template-columns: minmax(0, 1fr); }
  /* stacked: centre the grid over the now full-width card */
  .ts-inline .ts-dow,
  .ts-inline .ts-grid,
  .ts-inline .ts-cal-bar,
  .ts-inline .ts-branches,
  .ts-inline .ts-legend { max-width: 430px; margin-left: auto; margin-right: auto; }
  .ts-inline .ts-dow { margin-bottom: 8px; }
  /* stacked, the divider between the panes becomes horizontal */
  .ts-inline .ts-cal { border-bottom-color: var(--black, #000); }
}

@media (max-width: 640px) {
  .ts-inline { padding: 44px 0 36px; }
  .ts-inline-title { font-size: 24px; }
  .ts-inline .ts-cal,
  .ts-inline .ts-detail { padding: 18px 16px 22px; }
  .ts-inline .ts-dow,
  .ts-inline .ts-grid,
  .ts-inline .ts-cal-bar,
  .ts-inline .ts-branches,
  .ts-inline .ts-legend { max-width: none; }

  /* Three chips no longer fit one line at every width, so they share the row
     and wrap as a unit rather than leaving one chip stranded underneath. Taller
     too: this is the first thing pressed on the page, and on a phone it is
     pressed with a thumb.

     The colour badge adds about 24px to each chip, so here the row tightens to
     pay for it — smaller gap, less side padding, an 18px badge — and the three
     go on sharing one line. Anything too narrow for that wraps, which
     flex-wrap already handles. */
  .ts-branch-chips { gap: 6px; }
  .ts-branch { flex: 1 1 auto; height: 38px; gap: 6px; padding: 0 9px; }
  .ts-branch-ico { width: 18px; height: 18px; }

  /* the panel sits in the (now full-width) details pane; the graphic and the
     gaps come down so the CTA stays above the fold on a phone */
  .ts-blank-anim { width: 76px; height: 76px; margin-bottom: 18px; }
  .ts-blank-clock { width: 30px; height: 30px; }
  .ts-blank-title { font-size: 17px; }
  .ts-blank-rows { margin-top: 22px; gap: 8px; }
  .ts-blank-cta { margin-top: 22px; }
}

/* ---------- narrow screens ----------
   Below the two-column breakpoint the details pane drops under the
   calendar, and the launcher becomes a short tab pinned lower on the
   right so it never sits over the middle of the content. */
@media (max-width: 900px) {
  .ts-body { grid-template-columns: minmax(0, 1fr); }
  .ts-cal { border-right: none; border-bottom: 1px solid var(--black, #000); }
  .ts-detail { padding-top: 18px; }
}

@media (max-width: 640px) {
  .ts-modal { padding: 0; }
  .ts-dialog { max-width: none; max-height: 100vh; height: 100%; border: none; }
  .ts-dialog-title { font-size: 24px; }
  .ts-dialog-head { padding: 16px 16px 14px; }
  .ts-cal { padding: 16px; }
  .ts-detail { padding: 18px 16px 24px; }
  .ts-dow, .ts-grid { gap: 4px; }
  .ts-day { font-size: 13px; }

  .ts-launcher { top: auto; bottom: 18px; transform: none; }
  .ts-launcher-inner {
    flex-direction: row;
    width: auto;
    padding: 12px 14px;
  }
  .ts-launcher-text { font-size: 11px; }
  .ts-launcher-text br { display: none; }
  .ts-launcher-tip { display: none; }
  .ts-launcher:hover .ts-launcher-inner,
  .ts-launcher:focus-visible .ts-launcher-inner { transform: none; }
  .ts-launcher .ts-launcher-inner { animation: none; }
}

/* respect the OS "reduce motion" setting */
@media (prefers-reduced-motion: reduce) {
  .ts-launcher-inner,
  .ts-launcher-tip,
  .ts-modal-backdrop,
  .ts-dialog,
  /* the "all trainings" dialog opens with the same fade/rise pair */
  .ts-all-backdrop,
  .ts-all-dialog,
  .ts-day { animation: none !important; transition: none !important; }
  .ts-day--event:hover { transform: none; }
  .ts-upnext-more,
  .ts-all-more { transition: none !important; }
  /* the status pill on a preview row fades its border with the row's background */
  .ts-upnext-item .ts-upnext-status { transition: none !important; }

  /* The empty state keeps its meaning without the motion: the pending date
     settles on full opacity, the clock hands hold at their starting angle and
     the rows stop sweeping. Still reads as a calendar being written rather than
     a broken graphic. */
  .ts-inline.is-blank .ts-blank { animation: none !important; }
  .ts-blank-cal-dot { animation: none !important; opacity: 1; transform: none; }
  .ts-blank-hand { animation: none !important; }
  .ts-blank-row::after { animation: none !important; transform: translateX(-100%); }
  .ts-blank-cta,
  .ts-blank-cta svg { transition: none !important; }
  .ts-blank-cta:hover svg { transform: none; }
}
