// Calendar — concert list with view toggle (list / calendar) and filters.
// Multilingual via `t`; resolves {de,en,cs} fields with t.f().
const calNS = window.RoyHeyneDesignSystem_df1161;

/* Es gibt keine Reihen. Kapitälchen und Titel folgen derselben Quelle wie die
   Konzertkarte: die liturgische Zeit aus dem Datum und der gespaltene Kopf. */
const kalZeit = (c, t) => (calNS.Zeitangabe ? calNS.Zeitangabe(c.time, t.lang) : c.time);
const kalConf = (c) => (window.RH_confOf ? window.RH_confOf(c) : 'ev');
const kalAnlass = (c, lang) => { if (c.anlass) return (c.anlass[lang] || c.anlass.de || c.anlass); const a = calNS.KirchenjahrAnlass && calNS.KirchenjahrAnlass(c.iso, kalConf(c)); return a ? (a.label[lang] || a.label.de) : ''; };
const kalKopf = (c, t) => (calNS.Kartenkopf ? calNS.Kartenkopf(t.f(c.title), { place: t.f(c.place), city: t.f(c.city), instrument: t.f(c.instrument), anlass: kalAnlass(c, t.lang) }) : t.f(c.title));
const kalOrt = (c, t) => (calNS.Ortszeile ? calNS.Ortszeile(t.f(c.place), t.f(c.city)) : t.f(c.place));
const kalTeile = (c, t) => (calNS.Ortsteile ? calNS.Ortsteile(t.f(c.place), t.f(c.city)) : { kirche: t.f(c.place), stadt: t.f(c.city) });
/* Das Instrument nennt nicht noch einmal den Ort: „Ranft-Orgel, 1757“ bleibt; „Jehmlich-Orgel · Lauenstein“ → „Jehmlich-Orgel“. */
const kalInstrument = (c, t) => {
  const i = String(t.f(c.instrument) || '').trim(), s = String(t.f(c.city) || '').trim();
  if (!i || !s) return i;
  return i.replace(new RegExp('[\\s,·–-]*\\b' + s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\b[\\s,·–-]*', 'i'), ' ').replace(/\s{2,}/g, ' ').replace(/^[\s,·–-]+|[\s,·–-]+$/g, '').trim() || i;
};
/* Filter-Achse statt Reihe: die liturgische Zeit aus dem Datum. */
const kalAnlassObj = (c) => { const a = calNS.KirchenjahrAnlass && calNS.KirchenjahrAnlass(c.iso, kalConf(c)); return a ? a.label : null; };

function Filters({ series, place, onSeries, onPlace, seriesOpts, placeOpts, t }) {
  const { SelectField } = calNS;
  return (
    <div style={{ display: 'flex', gap: 20, flexWrap: 'wrap', alignItems: 'flex-end' }}>
      <div className="rh-filterfield" style={{ width: 260 }}>
        <SelectField label={t.f({ de: 'Kirchenjahr', en: 'Church year', cs: 'Církevní rok' })} value={series} onChange={(e) => onSeries(e.target.value)}>
          <option value="">{t('calendar.filter_all')}</option>
          {seriesOpts.map((s) => <option key={s.key} value={s.key}>{s.label}</option>)}
        </SelectField>
      </div>
      <div className="rh-filterfield" style={{ width: 220 }}>
        <SelectField label={t('detail.map')} value={place} onChange={(e) => onPlace(e.target.value)}>
          <option value="">—</option>
          {placeOpts.map((p) => <option key={p.key} value={p.key}>{p.label}</option>)}
        </SelectField>
      </div>
    </div>
  );
}

function ViewToggle({ view, onView, t }) {
  // Label als Sprach-Overlay: Breite = laengste Sprache → kein Springen beim Wechsel.
  const opt = (key, all) => (
    <button onClick={() => onView(key)} aria-pressed={view === key} style={{
      fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-14)', fontWeight: 500, cursor: 'pointer',
      padding: '8px 16px', border: '1px solid var(--border-hairline)',
      background: view === key ? 'var(--tinte)' : 'transparent',
      color: view === key ? 'var(--pergament-text)' : 'var(--schiefer)',
    }}>
      <span style={{ display: 'grid', justifyItems: 'center' }}>
        {['de','en','cs'].map((l) => (
          <span key={l} aria-hidden={l !== t.lang ? 'true' : undefined}
            style={{ gridArea: '1 / 1', whiteSpace: 'nowrap', visibility: l === t.lang ? 'visible' : 'hidden' }}>{all[l]}</span>
        ))}
      </span>
    </button>
  );
  return (
    <div style={{ display: 'inline-flex', borderRadius: 'var(--radius-sm)', overflow: 'hidden' }}>
      {opt('liste', window.RH_ALL('calendar.list'))}
      {opt('kalender', window.RH_ALL('calendar.cal'))}
    </div>
  );
}

function SeriesBand({ c, onNav, t }) {
  const { Badge } = calNS;
  // Mobil bricht das Band auf eine Textspalte um; ohne das spannt der nowrap-Pill
  // („Nächste Mittagsmusik · Mi 26. Aug") die Mittelspalte auf und das Band läuft
  // seitlich über (MOBILE.md — nicht verhandelbar). Gleiches Mittel wie ListRow.
  const isMobile = window.useIsMobile();
  const cur = window.RH_ORGELSOMMER_CURRENT;
  const months = ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'];
  const monsEn = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  const monsCs = ['led', 'úno', 'bře', 'dub', 'kvě', 'čvn', 'čvc', 'srp', 'zář', 'říj', 'lis', 'pro'];
  const ml = t.lang === 'en' ? monsEn : t.lang === 'cs' ? monsCs : months;
  const wdShort = cur ? (t.lang === 'en' ? ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'] : t.lang === 'cs' ? ['ne','po','út','st','čt','pá','so'] : ['So','Mo','Di','Mi','Do','Fr','Sa'])[new Date(cur.iso).getUTCDay()] : '';
  const nextLabel = cur ? `${wdShort} ${+cur.iso.slice(8, 10)}. ${ml[+cur.iso.slice(5, 7) - 1]} · ${kalZeit(c, t)}` : '';
  const nextWord = t.f({ de: 'Nächste Mittagsmusik', en: 'Next midday music', cs: 'Příští polední hudba' });
  const perfWord = t.f({ de: 'An der Orgel', en: 'At the organ', cs: 'U varhan' });
  const seriesWord = t.f({ de: 'Konzertreihe · seit 2020', en: 'Concert series · since 2020', cs: 'Koncertní řada · od 2020' });
  // Läuft die Saison gerade, sagt das Band es auch — sonst liest eine laufende
  // Reihe wie ein Archiveintrag. Zustand kommt aus RH_orgelsommerState().
  const osState = window.RH_orgelsommerState ? window.RH_orgelsommerState() : null;
  const running = !!(osState && osState.phase === 'laeuft');
  const weekCount = (window.RH_ORGELSOMMER || []).length;
  // Auf dem Messing-Wash des Bands reicht der Badge-Wash allein nicht (4,49:1) —
  // die deckende Pergamentfläche bringt den kleinen Text auf AA.
  const liveWord = running && cur && weekCount
    ? t.f({ de: 'Läuft jetzt · Woche ' + cur.week + ' von ' + weekCount,
            en: 'Running now · week ' + cur.week + ' of ' + weekCount,
            cs: 'Právě probíhá · ' + cur.week + '. z ' + weekCount + ' týdnů' })
    : '';
  return (
    <a href="#" onClick={(e) => { e.preventDefault(); onNav('detail', c.id); }}
      style={{ display: 'grid', gridTemplateColumns: isMobile ? '56px minmax(0, 1fr)' : '72px 1fr auto', gap: isMobile ? 14 : 24, alignItems: 'center', textDecoration: 'none', color: 'inherit',
        padding: isMobile ? '18px 16px' : '24px 26px', marginBottom: 26, borderRadius: 'var(--radius-lg)',
        background: 'linear-gradient(140deg, rgba(156,124,67,0.10), rgba(156,124,67,0.03))',
        border: '1px solid rgba(156,124,67,0.42)', boxShadow: 'var(--elev-2)' }}>
      <span aria-hidden="true" style={{ width: isMobile ? 'var(--medallion-sm)' : 'var(--medallion-lg)', height: isMobile ? 'var(--medallion-sm)' : 'var(--medallion-lg)', borderRadius: '50%', overflow: 'hidden',
        border: '1.5px solid var(--messing)', outline: '3px solid var(--surface-card)', background: 'var(--nachtschiefer)' }}>
        <img loading="lazy" decoding="async" src={c.porthole} alt="" aria-hidden="true" style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: c.portholePos || 'center', transform: c.portholeZoom && c.portholeZoom !== 1 ? 'scale(' + c.portholeZoom + ')' : undefined }} />
      </span>
      <div style={{ minWidth: 0 }}>
        <div className="rh-label" style={{ color: 'var(--messing-dunkel)', marginBottom: 5, display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
          <span aria-hidden="true" style={{ fontSize: 'var(--fs-14)' }}>↻</span>{seriesWord}
          {liveWord && (
            <Badge tone="accent" style={{ gap: 6, background: 'var(--pergament-hell)' }}>
              <span aria-hidden="true" className="rh-live-dot" />{liveWord}
            </Badge>
          )}
        </div>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: isMobile ? 22 : 27, color: 'var(--text-strong)', lineHeight: 1.12, letterSpacing: '-0.01em' }}>{t.f(c.series)}</div>
        <div style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-13-5)', color: 'var(--text-muted)', marginTop: 5 }}>{t.f(c.recurring)}</div>
        <div style={{ display: 'flex', alignItems: 'center', gap: isMobile ? 10 : 18, flexWrap: 'wrap', marginTop: 14 }}>
          <span style={{ display: 'inline-flex', alignItems: 'baseline', gap: 7, whiteSpace: isMobile ? 'normal' : 'nowrap', fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-13-5)', color: 'var(--messing-dunkel)', fontWeight: 600, padding: '5px 12px', borderRadius: 999, background: 'rgba(156,124,67,0.12)' }}>
            <span style={{ fontWeight: 400, color: 'var(--text-muted)' }}>{nextWord}</span>{nextLabel}
          </span>
          {c.performer && (
            <span style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-13-5)', color: 'var(--text-muted)' }}>{perfWord}: <span style={{ color: 'var(--text-strong)' }}>{t.f(c.performer)}</span></span>
          )}
        </div>
      </div>
      <div style={isMobile
        ? { gridColumn: '1 / -1', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, marginTop: 4, paddingTop: 12, borderTop: '1px solid rgba(156,124,67,0.28)' }
        : { textAlign: 'right', alignSelf: 'center' }}>
        <div style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-12-5)', color: 'var(--text-muted)', whiteSpace: 'nowrap' }}>{t.f({ de: 'Eintritt frei · Spenden', en: 'Free · donations', cs: 'Vstup volný · dary' })}</div>
        <div aria-hidden="true" style={{ fontSize: 'var(--fs-22)', color: 'var(--messing)', marginTop: isMobile ? 0 : 8 }}>→</div>
      </div>
    </a>
  );
}

function ListRow({ c, onNav, t }) {
  const { StatusDot } = calNS;
  const [hov, setHov] = React.useState(false);
  const isMobile = window.useIsMobile();
  const muted = c.status === 'vergangen';
  // Only surface a status chip when it carries real news. "geplant"/"vergangen"
  // repeat on every row (tab + dimming already say so) — pure noise, so hide them.
  const meaningful = c.status && c.status !== 'geplant' && c.status !== 'vergangen';
  const cur = c.recurring ? window.RH_ORGELSOMMER_CURRENT : null;
  const dayNum = cur ? cur.iso.slice(8, 10) : c.day;
  const monAbbr = cur ? ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'][+cur.iso.slice(5, 7) - 1] : t.f(c.mon);
  // Mobil: KEIN kollabiertes 5-Spalten-Tischraster (dort klebte die rechte Zelle
  //   an der Kante). Stattdessen eine linksbündige Flex-Karte — Bullauge links,
  //   Inhalt gestapelt, alles links. Flex, damit die globale Grid-Kollaps-Regel
  //   (grid-template-columns:1fr) nicht greift.
  if (isMobile) return (
    <a href="#" onClick={(e) => { e.preventDefault(); onNav('detail', c.id); }}
      style={{ display: 'flex', gap: 14, alignItems: 'flex-start', padding: '16px 4px', borderBottom: '1px solid var(--border-hairline)', textDecoration: 'none', color: 'inherit', opacity: muted ? 0.78 : 1 }}>
      <span aria-hidden="true" style={{ flex: 'none', width: 'var(--medallion-sm)', height: 'var(--medallion-sm)', borderRadius: '50%', overflow: 'hidden', border: '1.5px solid var(--messing)', outline: '2px solid var(--surface-card)', background: 'var(--nachtschiefer)', filter: muted ? 'grayscale(0.35)' : 'none' }}>
        <img loading="lazy" decoding="async" src={c.porthole} alt="" aria-hidden="true" style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: c.portholePos || 'center', transform: c.portholeZoom && c.portholeZoom !== 1 ? 'scale(' + c.portholeZoom + ')' : undefined }} />
      </span>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div className="rh-label" style={{ color: 'var(--messing-dunkel)', marginBottom: 4 }}>{kalAnlass(c, t.lang)}</div>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 'var(--fs-19)', lineHeight: 1.22, color: 'var(--text-strong)' }}>{kalKopf(c, t)}.</div>
        <div className="rh-num" style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-13)', fontWeight: 600, color: 'var(--messing-dunkel)', marginTop: 6 }}>{dayNum}. {monAbbr}{c.recurring ? '' : ` · ${kalZeit(c, t)}`}</div>
        <div style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-13)', color: 'var(--text-muted)', lineHeight: 1.5, marginTop: 4 }}>
          <span style={{ display: 'block', color: 'var(--text-strong)' }}>{kalTeile(c, t).kirche}</span>
          <span style={{ display: 'block' }}>{kalTeile(c, t).stadt}</span>
        </div>
        {meaningful ? (
          <div style={{ marginTop: 8 }}><StatusDot status={c.status} label={t('status.' + c.status)} /></div>
        ) : !muted ? (
          <div style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-12)', color: 'var(--text-muted)', marginTop: 8 }}>{t.f({ de: 'Eintritt frei · Spenden', en: 'Free · donations', cs: 'Vstup volný · dary' })}</div>
        ) : null}
      </div>
    </a>
  );
  return (
    <a href="#" onClick={(e) => { e.preventDefault(); onNav('detail', c.id); }}
      onMouseEnter={() => setHov(true)} onMouseLeave={() => setHov(false)}
      style={{ display: 'grid', gridTemplateColumns: '92px 64px 1fr 200px 150px', gap: 22, alignItems: 'center',
        padding: '22px 14px', borderBottom: '1px solid var(--border-hairline)', textDecoration: 'none', color: 'inherit',
        opacity: muted ? 0.78 : 1, borderRadius: 'var(--radius-md)',
        background: hov ? 'rgba(156,124,67,0.06)' : 'transparent', transition: 'background 160ms ease' }}>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', lineHeight: 1 }}>
        <span style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'var(--fs-40)', color: 'var(--text-strong)', letterSpacing: '-0.02em' }}>{dayNum}</span>
        <span className="rh-label" style={{ color: 'var(--messing-dunkel)', marginTop: 4 }}>{monAbbr}</span>
      </div>
      <span aria-hidden="true" style={{ width: 'var(--medallion-sm)', height: 'var(--medallion-sm)', borderRadius: '50%', overflow: 'hidden',
        border: '1.5px solid var(--messing)', outline: '2px solid var(--surface-card)', background: 'var(--nachtschiefer)',
        filter: muted ? 'grayscale(0.35)' : 'none' }}>
        <img loading="lazy" decoding="async" src={c.porthole} alt="" aria-hidden="true" style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: c.portholePos || 'center', transform: c.portholeZoom && c.portholeZoom !== 1 ? 'scale(' + c.portholeZoom + ')' : undefined }} />
      </span>
      <div>
        <div className="rh-label" style={{ color: 'var(--messing-dunkel)', marginBottom: 4 }}>{kalAnlass(c, t.lang)}</div>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 'var(--fs-22)', lineHeight: 1.2,
          color: hov ? 'var(--messing-dunkel)' : 'var(--text-strong)', transition: 'color 160ms ease' }}>{kalKopf(c, t)}.</div>
        <div className="rh-num" style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-13)', color: c.recurring ? 'var(--messing-dunkel)' : 'var(--text-muted)', marginTop: 4 }}>{c.recurring ? t.f(c.recurring) : `${t.f(c.weekday)} · ${kalZeit(c, t)}`}</div>
      </div>
      {/* Ort-Block: IMMER drei Zeilen — Kirche / Orgel / Ort. Jede Sprache traegt
          alle drei Felder, damit die Struktur pixelgleich bleibt. */}
      <div style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-14)', color: 'var(--text-muted)', lineHeight: 1.5 }}>
        <span role="link" tabIndex={0} title={t('detail.map')}
          onClick={(e) => { e.preventDefault(); e.stopPropagation(); window.open(window.RH_maps(window.RH_mapsQueryFor(c)), '_blank', 'noopener'); }}
          style={{ display: 'block', cursor: 'pointer', color: 'var(--text-strong)' }}>{kalTeile(c, t).kirche} ↗</span>
        <span style={{ display: 'block' }}>{kalInstrument(c, t)}</span>
        <span style={{ display: 'block' }}>{kalTeile(c, t).stadt}</span>
      </div>
      {/* Right column: a real signal (free entry · donations) for upcoming concerts,
          a genuine status chip only when there's news, plus a quiet arrow that
          warms to brass on hover — the affordance that says "this row opens". */}
      <div style={{ justifySelf: 'end', textAlign: 'right', display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 8 }}>
        {meaningful ? (
          <StatusDot status={c.status} label={t('status.' + c.status)} />
        ) : !muted ? (
          <span style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-12-5)', color: 'var(--text-muted)', whiteSpace: 'nowrap' }}>{t.f({ de: 'Eintritt frei · Spenden', en: 'Free · donations', cs: 'Vstup volný · dary' })}</span>
        ) : null}
        <span aria-hidden="true" style={{ fontSize: 'var(--fs-20)', lineHeight: 1,
          color: hov ? 'var(--messing)' : 'var(--border-strong)',
          transform: hov ? 'translateX(3px)' : 'none', transition: 'color 160ms ease, transform 160ms ease' }}>→</span>
      </div>
    </a>
  );
}

function CalendarGrid({ concerts, onNav, t }) {
  const keys = [];
  const byMonth = {};
  concerts.forEach((c) => { const k = t.monthKey(c.iso); (byMonth[k] = byMonth[k] || []).push(c); if (!keys.includes(k)) keys.push(k); });
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 40 }}>
      {keys.map((k) => (
        <div key={k}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 16, marginBottom: 18 }}>
            <h3 style={{ fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 'var(--fs-26)', margin: 0, color: 'var(--text-strong)', textTransform: 'capitalize' }}>{window.RH_pt(t.monthYear(byMonth[k][0].iso))}</h3>
            <span aria-hidden="true" style={{ color: 'var(--messing)', fontSize: 'var(--fs-15)' }}>❧</span>
            <span style={{ flex: 1, height: 1, background: 'var(--border-hairline)' }} />
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(230px, 1fr))', gap: 16 }}>
            {byMonth[k].map((c) => (
              <a key={c.id} href="#" onClick={(e) => { e.preventDefault(); onNav('detail', c.id); }}
                style={{ position: 'relative', display: 'block', padding: '18px 20px', background: 'var(--surface-card)',
                  border: '1px solid var(--border-hairline)', borderRadius: 'var(--radius-md)', textDecoration: 'none', color: 'inherit' }}>
                {c.porthole && (
                  <span aria-hidden="true" style={{ position: 'absolute', top: 14, right: 14, width: 44, height: 44, borderRadius: '50%', overflow: 'hidden',
                    border: '1.5px solid var(--messing)', outline: '2px solid var(--surface-card)', background: 'var(--nachtschiefer)' }}>
                    <img loading="lazy" decoding="async" src={c.porthole} alt="" aria-hidden="true" style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: c.portholePos || 'center', transform: c.portholeZoom && c.portholeZoom !== 1 ? 'scale(' + c.portholeZoom + ')' : undefined }} />
                  </span>
                )}
                <div className="rh-num" style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-13)', color: 'var(--messing-dunkel)', fontWeight: 600, letterSpacing: '0.04em' }}>{c.day}. · {kalZeit(c, t)}</div>
                <div style={{ fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 'var(--fs-19)', color: 'var(--text-strong)', margin: '8px 36px 6px 0', lineHeight: 1.2 }}>{kalKopf(c, t)}</div>
                <div style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-13)', color: 'var(--text-muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}><span role="link" tabIndex={0} title="Google Maps" onClick={(e) => { e.preventDefault(); e.stopPropagation(); window.open(window.RH_maps(window.RH_mapsQueryFor(c)), '_blank', 'noopener'); }} style={{ cursor: 'pointer', borderBottom: '1px solid var(--border-hairline)', padding: '12px 0', margin: '-12px 0' }}>{kalOrt(c, t)} ↗</span></div>
              </a>
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}

function CalHero({ t }) {
  const I = window.RH_IMG;
  return (
    <section style={{ position: 'relative', overflow: 'hidden', background: 'var(--scrim-2)' }}>
      <img loading="lazy" decoding="async" src={I.organStops} alt="" aria-hidden="true"
        style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center 50%', opacity: 0.42 }} />
      <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(96deg, rgba(18,16,12,0.92) 0%, rgba(18,16,12,0.6) 50%, rgba(18,16,12,0.4) 100%)' }} />
      <div style={{ position: 'relative', maxWidth: 'var(--container)', margin: '0 auto', padding: '120px var(--gutter) 64px' }}>
        <div className="rh-eyebrow rh-eyebrow--dark" style={{ marginBottom: 18 }}>{t('nav.konzerte')}</div>
        <h1 style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'clamp(2.6rem, 1.8rem + 3vw, 4.2rem)', color: 'var(--pergament-text)', margin: 0, lineHeight: 1.02 }}>{t('calendar.title')}.</h1>
        <p style={{ fontFamily: 'var(--font-body)', fontSize: 'var(--fs-19)', lineHeight: 1.7, color: 'rgba(236,230,216,0.84)', maxWidth: '52ch', marginTop: 18, minHeight: 'calc(1.7em * 3)' }}>{t('calendar.lead')}</p>
      </div>
    </section>
  );
}

function ServiceList({ t }) {
  const CC = { ev: { c: 'var(--bordeaux)', l: 'ev.' }, kath: { c: 'var(--messing)', l: 'kath.' } };
  const all = window.RH_DATA.services || [];
  // Fenster: alle kommenden Dienste + die letzten 2 vergangenen (gedämpft) —
  // genug Kontext, ohne ein endloses Archiv zu zeigen.
  // Automatik: vergangene Dienste fallen per Datum automatisch weg; es werden
  // zwingend nur die naechsten 5 aktuellen Dienste gezeigt (im Portal gepflegt).
  const items = all.filter((s) => !s.past).slice(0, 5);
  const L = t.lang;
  const note = L === 'en' ? 'As cantor, Roy Heyne is responsible for the organ and choral music in worship — in the Ev. Lutheran Parish of Osterzgebirge - Region Altenberg and, on select days, at catholic Mass in Dresden. All services are open to the public.' : L === 'cs' ? 'Jako kantor odpovídá Roy Heyne za varhanní a sborovou hudbu při bohoslužbách — v ev.-luter. farnosti Osterzgebirge - Region Altenberg a ve vybrané dny při katolických mších v Drážďanech. Všechny bohoslužby jsou veřejné.' : 'Als Kantor verantwortet Roy Heyne die Orgel- und Chormusik im Gottesdienst — im Ev.-Luth. Kirchspiel Osterzgebirge - Region Altenberg und, an einzelnen Tagen, in katholischen Messen in Dresden. Alle Gottesdienste sind öffentlich.';
  return (
    <div>
      <p style={{ fontFamily: 'var(--font-body)', fontSize: 'var(--fs-17)', color: 'var(--text-muted)', margin: '4px 0 10px' }}>{note}</p>
      {/* Die Liste zeigt das laufende KIRCHENJAHR, nicht das Kalenderjahr —
          das muss dastehen, sonst wirkt ein fehlender älterer Dienst wie ein
          Fehler. Das Archiv im Portal behält alles. */}
      <p className="rh-label" style={{ color: 'var(--messing-dunkel)', margin: '0 0 24px' }}>
        {(() => { const f = window.RH_kirchenjahrFenster ? window.RH_kirchenjahrFenster() : null;
          if (!f) return '';
          return t.f({ de: 'Kirchenjahr ' + f.jahr, en: 'Church year ' + f.jahr, cs: 'Liturgický rok ' + f.jahr }); })()}
      </p>
      {items.length === 0 && (
        <div style={{ padding: '40px 0', borderTop: '1px solid var(--border-hairline)', textAlign: 'center' }}>
          <div aria-hidden="true" style={{ fontFamily: 'var(--font-display)', fontSize: 'var(--fs-26)', color: 'var(--messing)', marginBottom: 12 }}>❧</div>
          <p style={{ fontFamily: 'var(--font-body)', fontSize: 'var(--fs-17)', color: 'var(--text-muted)', margin: 0, maxWidth: '48ch', marginLeft: 'auto', marginRight: 'auto' }}>
            {t.f({ de: 'Für das laufende Kirchenjahr sind derzeit keine Gottesdienste eingetragen.',
                   en: 'No services are currently listed for the present church year.',
                   cs: 'Pro probíhající liturgický rok nejsou uvedeny žádné bohoslužby.' })}
          </p>
        </div>
      )}
      <div style={{ borderTop: '1px solid var(--border-hairline)' }}>
        {items.map((s) => { const cc = CC[s.conf] || CC.ev; const lc = window.RH_LITURGY && window.RH_LITURGY.colorForService(s); return (
          <div key={s.id} style={{ position: 'relative', display: 'grid', gridTemplateColumns: '80px 1fr 220px', gap: 24, alignItems: 'center', padding: '18px 8px 18px 20px', borderBottom: '1px solid var(--border-hairline)', opacity: s.past ? 0.5 : 1 }}>
            {lc && <span aria-hidden="true" title={t.f(lc.name)} style={{ position: 'absolute', left: 0, top: 8, bottom: 8, width: 3, borderRadius: 2, background: lc.hex }} />}
            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', lineHeight: 1 }}>
              <span style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'var(--fs-34)', color: 'var(--text-strong)' }}>{s.day}</span>
              <span className="rh-label" style={{ color: 'var(--messing-dunkel)', marginTop: 4 }}>{s.mon}</span>
            </div>
            <div>
              <div style={{ display: 'inline-flex', alignItems: 'center', gap: 7, marginBottom: 4 }}>
                <span aria-hidden="true" style={{ width: 9, height: 9, borderRadius: '50%', background: cc.c }} />
                <span className="rh-label" style={{ color: cc.c }}>{cc.l}</span>
              </div>
              <div style={{ fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 'var(--fs-20)', color: 'var(--text-strong)', lineHeight: 1.2 }}>{s.title}</div>
              {(() => { const cy = window.RH_CY; if (!cy || !s.iso) return null; if (/Sonntag|So\. n\.|Trinitatis|Advent|Epiphan/i.test(s.title || '')) return null; const p = s.iso.split('-'); const lbl = cy.label(p[2] + '.' + (+p[1]) + '.' + p[0], s.conf); return lbl ? <div className="rh-num" style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-12-5)', color: 'var(--text-muted)', marginTop: 3 }}>{lbl}</div> : null; })()}
            </div>
            <div className="rh-num" style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-14)', color: 'var(--text-muted)' }}>{s.place} · {calNS.Zeitangabe ? calNS.Zeitangabe(s.time, 'de') : s.time}</div>
          </div>); })}
      </div>
    </div>
  );
}

function Chronicle({ t }) {
  const [offen, setOffen] = React.useState(false);
  // Automatik: die Chronik wächst von selbst. Jedes vergangene Konzert (RH_DATA.past)
  // wird nach Jahr gruppiert und in EXAKT dieser Formatierung eingetragen — sobald ein
  // Konzert vorbei ist, erscheint es hier. Die handgeschriebene Historie (RH_CHRONICLE,
  // z. B. 2020–2024) bleibt als Fundament für Jahre ohne Einzeldaten erhalten.
  const _MO = ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'];
  const live = {};
  (window.RH_DATA.past.filter(window.RH_istOeffentlich) || []).forEach((c) => {
    const y = (c.iso || '').slice(0, 4); if (!y) return;
    const d = new Date(c.iso + 'T12:00:00');
    (live[y] = live[y] || []).push({
      iso: c.iso,
      d: String(d.getDate()).padStart(2, '0') + '. ' + _MO[d.getMonth()],
      t: c.title,
      w: kalOrt(c, t),
    });
  });
  const staticYears = {};
  (window.RH_CHRONICLE || []).forEach((yr) => { staticYears[yr.year] = yr.items; });
  // Vollständigkeit: die kuratierte Chronik (RH_CHRONICLE) ist die verbindliche,
  // vollständige Quelle. Live-archivierte Konzerte (RH_DATA.past) werden je Jahr
  // nur ergänzt, wenn ihr Datum dort noch nicht steht (kein Verlust, kein Duplikat).
  const _key = (d) => { const m = (typeof d === 'string') && d.match(/^(\d{2})\.(\d{2})\./); return m ? m[2] + '-' + m[1] : null; };
  const allYears = Array.from(new Set([...Object.keys(live), ...Object.keys(staticYears)]));
  const years = allYears
    .map((y) => {
      const st = staticYears[y] || [];
      const stKeys = new Set(st.map((it) => _key(it.d)).filter(Boolean));
      const extra = (live[y] || []).filter((it) => !stKeys.has((it.iso || '').slice(5, 10)));
      extra.sort((a, b) => (a.iso < b.iso ? 1 : -1));
      const items = st.length ? st.concat(extra) : (live[y] || []).slice().sort((a, b) => (a.iso < b.iso ? 1 : -1));
      return { year: Number(y), items: items };
    })
    .sort((a, b) => b.year - a.year);
  return (
    <div style={{ marginTop: 'clamp(24px, 3vw, 40px)' }}>
      <div className="rh-label" style={{ color: 'var(--messing-dunkel)', marginBottom: 10 }}>{t.f({ de: 'Chronik', en: 'Chronicle', cs: 'Kronika' })}</div>
      <h2 style={{ fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 'clamp(1.7rem, 1.3rem + 1.2vw, 2.4rem)', color: 'var(--text-strong)', margin: '0 0 10px' }}>{t.f({ de: 'Konzerte seit 2020', en: 'Concerts since 2020', cs: 'Koncerty od roku 2020' })}.</h2>
      <p style={{ fontFamily: 'var(--font-body)', fontSize: 'var(--fs-16-5)', lineHeight: 1.7, color: 'var(--text-muted)', margin: '0 0 22px', maxWidth: '62ch' }}>{t.f({ de: 'Ein Überblick der vergangenen Spielzeiten — von Geising und Lauenstein bis ins böhmische Prag, Osek und Smolnice.', en: 'An overview of past seasons — from Geising and Lauenstein to Prague, Osek and Smolnice in Bohemia.', cs: 'Přehled minulých sezón — od Geisingu a Lauensteinu až po českou Prahu, Osek a Smolnice.' })}</p>
      {/* Die Chronik ist Beleg, nicht Lesestoff: standardmäßig eingeklappt, mit
          echter Zahl aus den Daten. Öffnen entfaltet sie weich (rh-settle-in);
          die Schaltfläche ist die einzige Zierde. */}
      {(() => {
        const anzahl = years.reduce((a, y) => a + (y.items ? y.items.length : 0), 0);
        const label = offen
          ? t.f({ de: 'Chronik schließen', en: 'Close chronicle', cs: 'Zavřít kroniku' })
          : t.f({ de: 'Chronik öffnen — ' + anzahl + ' Konzerte in ' + years.length + ' Spielzeiten', en: 'Open chronicle — ' + anzahl + ' concerts in ' + years.length + ' seasons', cs: 'Otevřít kroniku — ' + anzahl + ' koncertů v ' + years.length + ' sezónách' });
        return (
          <button type="button" onClick={() => setOffen(!offen)} aria-expanded={offen}
            style={{ display: 'inline-flex', alignItems: 'center', gap: 12, minHeight: 44, padding: '0 2px', margin: '0 0 8px', background: 'none', border: 'none', cursor: 'pointer',
              fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-14-5)', fontWeight: 500, color: 'var(--messing-dunkel)', borderBottom: '1px solid var(--messing)' }}>
            {label}
            <span aria-hidden="true" style={{ display: 'inline-block', transform: offen ? 'rotate(180deg)' : 'none', transition: 'transform 320ms cubic-bezier(0.32, 0.72, 0, 1)', color: 'var(--messing)' }}>⌄</span>
          </button>
        );
      })()}
      {offen && (
      <div className="rh-settle" style={{ display: 'flex', flexDirection: 'column', gap: 'clamp(30px, 3.5vw, 52px)', marginTop: 30 }}>
        {years.map((yr) => (
          <div key={yr.year} style={{ display: 'grid', gridTemplateColumns: '96px 1fr', gap: 'clamp(14px, 3vw, 40px)', alignItems: 'start' }}>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 'clamp(1.9rem, 1.4rem + 1vw, 2.7rem)', color: 'var(--messing)', lineHeight: 1 }}>{yr.year}</div>
            <div style={{ borderTop: '1px solid var(--border-hairline)' }}>
              {yr.items.map((it, i) => (
                <div key={i} style={{ display: 'grid', gridTemplateColumns: '92px 1fr', gap: 16, padding: '12px 0', borderBottom: '1px solid var(--border-hairline)', alignItems: 'baseline' }}>
                  <span className="rh-num" style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-13-5)', color: 'var(--text-muted)', whiteSpace: 'nowrap' }}>{it.d}</span>
                  <span style={{ fontFamily: 'var(--font-body)', fontSize: 'var(--fs-16-5)', lineHeight: 1.55 }}>
                    <span style={{ color: 'var(--text-strong)' }}>{t.f(it.t)}</span>
                    <span style={{ color: 'var(--text-muted)' }}>{' · ' + it.w}</span>
                  </span>
                </div>
              ))}
            </div>
          </div>
        ))}
      </div>
      )}
    </div>
  );
}

function Calendar({ onNav, t, initialFilter }) {
  const { Button } = calNS;
  const [tense, setTense] = React.useState(initialFilter === 'dienste' ? 'dienste' : 'kommend');
  const all = tense === 'dienste' ? [] : (tense === 'kommend' ? window.RH_DATA.concerts.filter(window.RH_istOeffentlich) : window.RH_DATA.past.filter(window.RH_istOeffentlich));
  const [view, setView] = React.useState('liste');
  const [series, setSeries] = React.useState('');
  const [place, setPlace] = React.useState('');
  const [instr, setInstr] = React.useState(initialFilter && initialFilter !== 'dienste' ? initialFilter : '');
  // B2 (freigegeben): Mobil liegen die beiden Filter hinter einem Aufklapper —
  // Konzerte rücken nach oben, kein Funktionsverlust.
  const isMobile = window.useIsMobile();
  const [filtersOpen, setFiltersOpen] = React.useState(false);
  React.useEffect(() => {
    if (initialFilter === 'dienste') { setTense('dienste'); setInstr(''); }
    else setInstr(initialFilter || '');
  }, [initialFilter]);
  // build unique option lists keyed by the German value, labelled per language
  const uniq = (sel) => {
    const seen = {}; const out = [];
    all.forEach((c) => { const k = sel(c).de; if (!seen[k]) { seen[k] = 1; out.push({ key: k, label: t.f(sel(c)) }); } });
    return out;
  };
  const seriesOpts = (() => { const seen = {}, out = []; all.forEach((c) => { const o = kalAnlassObj(c); if (o && !seen[o.de]) { seen[o.de] = 1; out.push({ key: o.de, label: t.f(o) }); } }); return out; })();
  const placeOpts = uniq((c) => c.city);
  const filtered = all.filter((c) => (!series || (kalAnlassObj(c) || {}).de === series) && (!place || c.city.de === place)
    && (!instr || (c.instrument && c.instrument.de && c.instrument.de.indexOf(instr) !== -1)));

  // Reiter-Label als Sprach-Overlay: alle drei Sprachen liegen uebereinander,
  // die Breite entspricht der laengsten — so springt beim Sprachwechsel nichts.
  const TenseTab = ({ k, all }) => (
    <button onClick={() => { setTense(k); setSeries(''); setPlace(''); }}
      style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '6px 2px',
        fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-15)', fontWeight: 500,
        color: tense === k ? 'var(--text-strong)' : 'var(--text-muted)',
        borderBottom: tense === k ? '2px solid var(--messing)' : '2px solid transparent' }}>
      <span style={{ display: 'grid', justifyItems: 'center' }}>
        {['de','en','cs'].map((l) => (
          <span key={l} aria-hidden={l !== t.lang ? 'true' : undefined}
            style={{ gridArea: '1 / 1', whiteSpace: 'nowrap', visibility: l === t.lang ? 'visible' : 'hidden' }}>{all[l]}</span>
        ))}
      </span>
    </button>
  );

  return (
    <div>
      <CalHero t={t} />
      <div style={{ maxWidth: 'var(--container)', margin: '0 auto', padding: '40px var(--gutter) 96px' }}>
        <div style={{ display: 'flex', gap: 28, marginBottom: 8, borderBottom: '1px solid var(--border-hairline)', paddingBottom: 2 }}>
          <TenseTab k="kommend" all={window.RH_ALL('calendar.upcoming')} />
          <TenseTab k="vergangen" all={window.RH_ALL('calendar.past')} />
          <TenseTab k="dienste" all={{ de: 'Dienste', en: 'Services', cs: 'Bohoslužby' }} />
        </div>
        {instr && (
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 10, marginTop: 20, padding: '7px 14px', borderRadius: 999, background: 'rgba(156,124,67,0.12)', border: '1px solid var(--messing)' }}>
            <span style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-13-5)', color: 'var(--messing-dunkel)' }}>{t('detail.instrument')}: {instr}</span>
            <button onClick={() => setInstr('')} aria-label="×" style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--messing-dunkel)', fontSize: 'var(--fs-16)', lineHeight: 1, padding: 0 }}>×</button>
          </div>
        )}
        {tense === 'kommend' && (isMobile ? (
          <div style={{ margin: '24px 0 28px' }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
              <button onClick={() => setFiltersOpen((o) => !o)} aria-expanded={filtersOpen}
                style={{ display: 'inline-flex', alignItems: 'center', gap: 9, fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-14)', fontWeight: 500,
                  color: 'var(--text-strong)', background: filtersOpen ? 'var(--surface-card)' : 'none', cursor: 'pointer',
                  border: '1px solid var(--border-hairline)', borderRadius: 'var(--radius-sm)', padding: '10px 18px' }}>
                {t.f({ de: 'Filtern', en: 'Filter', cs: 'Filtrovat' })}
                {(series || place) ? <span aria-hidden="true" style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--messing)' }} /> : null}
                <span aria-hidden="true" style={{ fontSize: 'var(--fs-12)', color: 'var(--text-muted)' }}>{filtersOpen ? '▴' : '▾'}</span>
              </button>
              <ViewToggle view={view} onView={setView} t={t} />
            </div>
            {filtersOpen && (
              <div style={{ marginTop: 14, padding: '18px 16px', border: '1px solid var(--border-hairline)', borderRadius: 'var(--radius-md)', background: 'var(--surface-card)', display: 'grid', gap: 16 }}>
                <Filters series={series} place={place} onSeries={setSeries} onPlace={setPlace} seriesOpts={seriesOpts} placeOpts={placeOpts} t={t} />
                {tense === 'kommend' && <div><Button variant="outline" size="sm" onClick={() => window.RH_icsDownload(filtered, 'roy-heyne-konzerte', t.lang)} iconAfter={<span>↧</span>}>{t('calendar.ical')}</Button></div>}
              </div>
            )}
          </div>
        ) : (<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', gap: 24, margin: '28px 0', flexWrap: 'wrap' }}>
          <Filters series={series} place={place} onSeries={setSeries} onPlace={setPlace} seriesOpts={seriesOpts} placeOpts={placeOpts} t={t} />
          <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
            {tense === 'kommend' && <Button variant="outline" size="sm" onClick={() => window.RH_icsDownload(filtered, 'roy-heyne-konzerte', t.lang)} iconAfter={<span>↧</span>}>{t('calendar.ical')}</Button>}
            <ViewToggle view={view} onView={setView} t={t} />
          </div>
        </div>))}
        {tense === 'dienste' ? <ServiceList t={t} /> : tense === 'vergangen' ? <Chronicle t={t} /> : filtered.length === 0 ? (
          <div style={{ padding: '56px 0', textAlign: 'center', borderTop: '1px solid var(--border-hairline)' }}>
            <div aria-hidden="true" style={{ fontFamily: 'var(--font-display)', fontSize: 'var(--fs-28)', color: 'var(--messing)', marginBottom: 14 }}>❧</div>
            <p style={{ fontFamily: 'var(--font-body)', fontSize: 'var(--fs-17)', color: 'var(--text-muted)', margin: 0 }}>
              {t.f({ de: 'Für diese Auswahl sind derzeit keine Termine eingetragen.', en: 'No dates are currently listed for this selection.', cs: 'Pro tento výběr nejsou momentálně uvedeny žádné termíny.' })}
            </p>
            <p style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-14)', color: 'var(--text-muted)', margin: '10px 0 0' }}>
              {t.f({ de: 'Neue Konzerte folgen in Kürze — oder Auswahl zurücksetzen.', en: 'New concerts will follow shortly — or reset the selection.', cs: 'Nové koncerty budou brzy doplněny — nebo zrušte výběr.' })}
            </p>
          </div>
        ) : view === 'liste' ? (
          (() => {
            const band = tense === 'kommend' ? filtered.find((c) => c.recurring) : null;
            const rows = band ? filtered.filter((c) => c !== band) : filtered;
            return (
              <div>
                {band && <SeriesBand c={band} onNav={onNav} t={t} />}
                <div style={{ borderTop: '1px solid var(--border-hairline)' }}>
                  {rows.map((c) => <ListRow key={c.id} c={c} onNav={onNav} t={t} />)}
                </div>
              </div>
            );
          })()
        ) : (
          <CalendarGrid concerts={filtered} onNav={onNav} t={t} />
        )}
        {tense === 'kommend' && (
          <button type="button" onClick={() => { setTense('vergangen'); setSeries(''); setPlace(''); window.scrollTo({ top: 0 }); }}
            aria-label={t.f({ de: 'Zum Archiv — Konzerte seit 2020', en: 'To the archive — concerts since 2020', cs: 'Do archivu — koncerty od roku 2020' })}
            style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 20, width: '100%', textAlign: 'left', cursor: 'pointer', marginTop: 48, padding: 'clamp(22px, 3vw, 32px)', background: 'var(--surface-card)', border: '1px solid var(--border-hairline)', borderRadius: 'var(--radius-md)', transition: 'box-shadow var(--dur-base) var(--ease-standard), border-color var(--dur-base) var(--ease-standard)' }}
            onMouseEnter={(e) => { e.currentTarget.style.boxShadow = 'var(--elev-1)'; e.currentTarget.style.borderColor = 'var(--messing)'; }}
            onMouseLeave={(e) => { e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.borderColor = 'var(--border-hairline)'; }}>
            <span>
              <span className="rh-label" style={{ color: 'var(--messing-dunkel)', display: 'block', marginBottom: 8 }}>{t.f({ de: 'Archiv', en: 'Archive', cs: 'Archiv' })}</span>
              <span style={{ fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 'clamp(1.4rem, 1.1rem + 1vw, 2rem)', color: 'var(--text-strong)', display: 'block', lineHeight: 1.1 }}>{t.f({ de: 'Konzerte seit 2020', en: 'Concerts since 2020', cs: 'Koncerty od roku 2020' })}</span>
              <span style={{ fontFamily: 'var(--font-body)', fontSize: 'var(--fs-15-5)', color: 'var(--text-muted)', display: 'block', marginTop: 8, maxWidth: '54ch' }}>{t.f({ de: 'Jahr für Jahr — die vergangenen Spielzeiten als Chronik.', en: 'Year by year — the past seasons as a chronicle.', cs: 'Rok za rokem — minulé sezóny jako kronika.' })}</span>
            </span>
            <span aria-hidden="true" style={{ flexShrink: 0, fontFamily: 'var(--font-display)', fontSize: 'var(--fs-30)', color: 'var(--messing)' }}>→</span>
          </button>
        )}
        <p style={{ fontFamily: 'var(--font-ui)', fontSize: 'var(--fs-13)', color: 'var(--text-muted)', textAlign: 'center', margin: '52px 0 0', lineHeight: 1.6 }}>{t.f({ de: 'Trotz größter Sorgfalt sind alle Angaben ohne Gewähr.', en: 'Despite every care, all information is without guarantee.', cs: 'Přes veškerou péči jsou všechny údaje bez záruky.' })}</p>
      </div>
    </div>
  );
}

Object.assign(window, { Calendar });
