Compare commits
2 Commits
d913d0c145
...
dev_aaron
| Author | SHA1 | Date | |
|---|---|---|---|
| f44be56a8e | |||
| f8fc262290 |
BIN
img/youtube-logo.png
LFS
Normal file
BIN
img/youtube-logo.png
LFS
Normal file
Binary file not shown.
367
main.js
367
main.js
@@ -65,7 +65,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
fsk: "6",
|
fsk: "6",
|
||||||
description: "In Walt Disney Animation Studios’ \"Zoomania 2\" geraten die tierischen Detektive Judy Hopps und Nick Wilde auf die rätselhafte Spur eines geheimnisvollen Reptils, das in Zoomania auftaucht und die Metropole völlig auf den Kopf stellt: Gary De’Snake! ",
|
description: "In Walt Disney Animation Studios’ \"Zoomania 2\" geraten die tierischen Detektive Judy Hopps und Nick Wilde auf die rätselhafte Spur eines geheimnisvollen Reptils, das in Zoomania auftaucht und die Metropole völlig auf den Kopf stellt: Gary De’Snake! ",
|
||||||
poster: "img/Zoomania-2.jpg",
|
poster: "img/Zoomania-2.jpg",
|
||||||
backdrop: "img/Zoomania-2.jpg"
|
backdrop: "img/Zoomania-2.jpg",
|
||||||
|
trailerYoutubeId: "https://www.youtube.com/watch?v=RPE_6KbMgYU&pp=ygUZem9vbWFuaWEgMiB0cmFpbGVyIGdlcm1hbg%3D%3D",
|
||||||
|
actors: ["Name 1", "Name 2", "Name 3"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Shelter",
|
title: "Shelter",
|
||||||
@@ -74,7 +76,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
fsk: "16",
|
fsk: "16",
|
||||||
description: "Michael Mason, ein untergetauchter Elite-Agent, lebt auf einer abgelegenen Insel in Schottland. Als er in einem schweren Sturm ein Mädchen vor dem Ertrinken rettet, setzt er damit eine Kette von Ereignissen in Gang, die sein Versteck enttarnen und ihn zurück in die Welt zwingen. Dort muss er nicht nur um das Überleben der Teenagerin kämpfen, sondern sich auch den Dämonen seiner Vergangenheit stellen…",
|
description: "Michael Mason, ein untergetauchter Elite-Agent, lebt auf einer abgelegenen Insel in Schottland. Als er in einem schweren Sturm ein Mädchen vor dem Ertrinken rettet, setzt er damit eine Kette von Ereignissen in Gang, die sein Versteck enttarnen und ihn zurück in die Welt zwingen. Dort muss er nicht nur um das Überleben der Teenagerin kämpfen, sondern sich auch den Dämonen seiner Vergangenheit stellen…",
|
||||||
poster: "img/shelter.jpg",
|
poster: "img/shelter.jpg",
|
||||||
backdrop: "img/shelter.jpg"
|
backdrop: "img/shelter.jpg",
|
||||||
|
trailerYoutubeId: "https://www.youtube.com/watch?v=_DgEucbPMZI&pp=ygUWc2hlbHRlciB0cmFpbGVyIGdlcm1hbg%3D%3D",
|
||||||
|
actors: ["Name 1", "Name 2", "Name 3"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Mutiny",
|
title: "Mutiny",
|
||||||
@@ -83,7 +87,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
fsk: "?",
|
fsk: "?",
|
||||||
description: "Als sein milliardenschwerer Boss vor seinen Augen einem Mordkomplott zum Opfer fällt, wird Cole Reed (Jason Statham) für das Verbrechen verantwortlich gemacht. Im Bestreben dessen Tod zu rächen und die Täter zu überführen, gelangt Reed an Bord eines Frachters und stößt dabei auf eine internationale Verschwörung. Im Alleingang startet Cole eine gnadenlose Racheaktion auf hoher See…",
|
description: "Als sein milliardenschwerer Boss vor seinen Augen einem Mordkomplott zum Opfer fällt, wird Cole Reed (Jason Statham) für das Verbrechen verantwortlich gemacht. Im Bestreben dessen Tod zu rächen und die Täter zu überführen, gelangt Reed an Bord eines Frachters und stößt dabei auf eine internationale Verschwörung. Im Alleingang startet Cole eine gnadenlose Racheaktion auf hoher See…",
|
||||||
poster: "img/mutiny.jpg",
|
poster: "img/mutiny.jpg",
|
||||||
backdrop: "img/mutiny.jpg"
|
backdrop: "img/mutiny.jpg",
|
||||||
|
trailerYoutubeId: "https://www.youtube.com/watch?v=DU2cBNrvHA4&pp=ygUObXV0aW55IHRyYWlsZXI%3D",
|
||||||
|
actors: ["Name 1", "Name 2", "Name 3"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Der Austronaut - Project Hail Mary",
|
title: "Der Austronaut - Project Hail Mary",
|
||||||
@@ -92,7 +98,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
fsk: "12",
|
fsk: "12",
|
||||||
description: "Der Naturwissenschaftslehrer Ryland Grace wacht eines Tages auf einem Raumschiff auf - Lichtjahre von zu Hause entfernt und ohne Erinnerung daran, wer er ist oder wie er dorthin gekommen ist.",
|
description: "Der Naturwissenschaftslehrer Ryland Grace wacht eines Tages auf einem Raumschiff auf - Lichtjahre von zu Hause entfernt und ohne Erinnerung daran, wer er ist oder wie er dorthin gekommen ist.",
|
||||||
poster: "img/derAustronaut.jpg",
|
poster: "img/derAustronaut.jpg",
|
||||||
backdrop: "img/derAustronaut.jpg"
|
backdrop: "img/derAustronaut.jpg",
|
||||||
|
trailerYoutubeId: "https://www.youtube.com/watch?v=-KXQttVDPyk&pp=ygUdZGVyIGFzdHJvbmF1dCB0cmFpbGVyIGRldXRzY2g%3D",
|
||||||
|
actors: ["Name 1", "Name 2", "Name 3"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Der Super Mario Galaxy Film",
|
title: "Der Super Mario Galaxy Film",
|
||||||
@@ -101,7 +109,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
fsk: "6",
|
fsk: "6",
|
||||||
description: "''Der Super Mario Galaxy Film'' ist der neue Animationsfilm, basierend auf der Welt von „Super Mario Bros.“!",
|
description: "''Der Super Mario Galaxy Film'' ist der neue Animationsfilm, basierend auf der Welt von „Super Mario Bros.“!",
|
||||||
poster: "img/mariogalaxy.jpg",
|
poster: "img/mariogalaxy.jpg",
|
||||||
backdrop: "img/mariogalaxy.jpg"
|
backdrop: "img/mariogalaxy.jpg",
|
||||||
|
trailerYoutubeId:"https://www.youtube.com/watch?v=RtoRPSh0jvM&pp=ygUrZGVyIHN1cGVyIG1hcmlvIGdhbGF4eSBmaWxtIHRyYWlsZXIgZGV1dHNjaA%3D%3D",
|
||||||
|
actors: ["Name 1", "Name 2", "Name 3"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Hoppers",
|
title: "Hoppers",
|
||||||
@@ -110,7 +120,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
fsk: "6",
|
fsk: "6",
|
||||||
description: "In Disney Pixars ''Hoppers'' hoppt Tierfreundin Mabel mithilfe neuester Technologie in einen Roboterbiber und macht die Tierwelt (un)sicher! ",
|
description: "In Disney Pixars ''Hoppers'' hoppt Tierfreundin Mabel mithilfe neuester Technologie in einen Roboterbiber und macht die Tierwelt (un)sicher! ",
|
||||||
poster: "img/hoppers.jpg",
|
poster: "img/hoppers.jpg",
|
||||||
backdrop: "img/hoppers.jpg"
|
backdrop: "img/hoppers.jpg",
|
||||||
|
trailerYoutubeId: "https://www.youtube.com/watch?v=WqTZZcPe5R0&pp=ygUPaG9wcGVycyB0cmFpbGVy",
|
||||||
|
actors: ["Name 1", "Name 2", "Name 3"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Solo Mio",
|
title: "Solo Mio",
|
||||||
@@ -119,7 +131,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
fsk: "12",
|
fsk: "12",
|
||||||
description: "Nachdem er in Rom am Altar stehen gelassen wurde, beschließt ein Mann, allein in die Flitterwochen zu fahren.",
|
description: "Nachdem er in Rom am Altar stehen gelassen wurde, beschließt ein Mann, allein in die Flitterwochen zu fahren.",
|
||||||
poster: "img/solomio.png",
|
poster: "img/solomio.png",
|
||||||
backdrop: "img/solomio.png"
|
backdrop: "img/solomio.png",
|
||||||
|
trailerYoutubeId: "https://www.youtube.com/watch?v=tYtiinTvE3s&pp=ygUYc29sZSBtaW8gdHJhaWxlciBkZXV0c2No",
|
||||||
|
actors: ["Name 1", "Name 2", "Name 3"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "The Mandalorian and Grogu",
|
title: "The Mandalorian and Grogu",
|
||||||
@@ -128,7 +142,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
fsk: "?",
|
fsk: "?",
|
||||||
description: "Während die Neue Republik daran arbeitet, alles zu schützen, wofür die Rebellion gekämpft hat, sichern sie sich die Unterstützung des legendären mandalorianischen Kopfgeldjägers Din Djarin und seines jungen Lehrlings Grogu. ",
|
description: "Während die Neue Republik daran arbeitet, alles zu schützen, wofür die Rebellion gekämpft hat, sichern sie sich die Unterstützung des legendären mandalorianischen Kopfgeldjägers Din Djarin und seines jungen Lehrlings Grogu. ",
|
||||||
poster: "img/mandalorian.jpeg",
|
poster: "img/mandalorian.jpeg",
|
||||||
backdrop: "img/mandalorian.jpeg"
|
backdrop: "img/mandalorian.jpeg",
|
||||||
|
trailerYoutubeId: "https://www.youtube.com/watch?v=cMJMtGccVfs&pp=ygUlbWFuZGFsb3JpYW4gYW5kIGdyb2d1IHRyYWlsZXIgZGV1dHNjaA%3D%3D",
|
||||||
|
actors: ["Name 1", "Name 2", "Name 3"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Glennkill - Ein Schafskrimi",
|
title: "Glennkill - Ein Schafskrimi",
|
||||||
@@ -137,7 +153,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
fsk: "?",
|
fsk: "?",
|
||||||
description: "Schäfer George liest seinen geliebten Schafen jeden Abend Krimis vor und nimmt an, dass sie kein Wort davon verstehen. Doch als ein mysteriöser Vorfall das friedliche Leben auf der Farm durchbricht, wird den Schafen bewusst, dass sie selbst nun die Ermittlungen übernehmen müssen. Also folgen sie der Spur der Beweise und machen menschliche Verdächtige ausfindig.",
|
description: "Schäfer George liest seinen geliebten Schafen jeden Abend Krimis vor und nimmt an, dass sie kein Wort davon verstehen. Doch als ein mysteriöser Vorfall das friedliche Leben auf der Farm durchbricht, wird den Schafen bewusst, dass sie selbst nun die Ermittlungen übernehmen müssen. Also folgen sie der Spur der Beweise und machen menschliche Verdächtige ausfindig.",
|
||||||
poster: "img/glennkill.jpg",
|
poster: "img/glennkill.jpg",
|
||||||
backdrop: "img/glennkill.jpg"
|
backdrop: "img/glennkill.jpg",
|
||||||
|
trailerYoutubeId: "https://www.youtube.com/watch?v=Ylu6xVTHAlk&pp=ygUZZ2xlbm5raWxsIGVpbiBzY2hhZnNrcmltaQ%3D%3D",
|
||||||
|
actors: ["Name 1", "Name 2", "Name 3"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Masters of the Universe",
|
title: "Masters of the Universe",
|
||||||
@@ -146,7 +164,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
fsk: "?",
|
fsk: "?",
|
||||||
description: "Nach 15 Jahren der Trennung führt das Schwert der Macht Prinz Adam zurück nach Eternia und er entdeckt, dass seine Heimat unter der Herrschaft von Skeletor in Trümmern liegt.",
|
description: "Nach 15 Jahren der Trennung führt das Schwert der Macht Prinz Adam zurück nach Eternia und er entdeckt, dass seine Heimat unter der Herrschaft von Skeletor in Trümmern liegt.",
|
||||||
poster: "img/masteruniverse.jpg",
|
poster: "img/masteruniverse.jpg",
|
||||||
backdrop: "img/masteruniverse.jpg"
|
backdrop: "img/masteruniverse.jpg",
|
||||||
|
trailerYoutubeId: "https://www.youtube.com/watch?v=COJU2b4XZ8U&pp=ygUfbWFzdGVycyBvZiB0aGUgdW5pdmVyc2UgdHJhaWxlcg%3D%3D",
|
||||||
|
actors: ["Name 1", "Name 2", "Name 3"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Minions and Monsters",
|
title: "Minions and Monsters",
|
||||||
@@ -155,7 +175,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
fsk: "?",
|
fsk: "?",
|
||||||
description: "MINIONS & MONSTER erzählt die abgefahrene, aberwitzige und natürlich absolut wahre Geschichte von den Minions und wie sie Hollywood erobern, Filmstars werden, alles verlieren, Monster auf die Welt loslassen und sich dann heldenhaft daranmachen, den Planeten vor genau dem Chaos zu retten, das sie selbst angerichtet haben. ",
|
description: "MINIONS & MONSTER erzählt die abgefahrene, aberwitzige und natürlich absolut wahre Geschichte von den Minions und wie sie Hollywood erobern, Filmstars werden, alles verlieren, Monster auf die Welt loslassen und sich dann heldenhaft daranmachen, den Planeten vor genau dem Chaos zu retten, das sie selbst angerichtet haben. ",
|
||||||
poster: "img/minionsmonsters.jpg",
|
poster: "img/minionsmonsters.jpg",
|
||||||
backdrop: "img/minionsmonsters.jpg"
|
backdrop: "img/minionsmonsters.jpg",
|
||||||
|
trailerYoutubeId: "https://www.youtube.com/watch?v=a31E7qNxwtI&pp=ygUcbWluaW9ucyBhbmQgbW9uc3RlcnMgdHJhaWxlctIHCQkECwGHKiGM7w%3D%3D",
|
||||||
|
actors: ["Name 1", "Name 2", "Name 3"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Spider Man - Brand New Day",
|
title: "Spider Man - Brand New Day",
|
||||||
@@ -334,6 +356,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
let heroItems = [];
|
let heroItems = [];
|
||||||
let heroIndex = 0;
|
let heroIndex = 0;
|
||||||
let heroTimer = null;
|
let heroTimer = null;
|
||||||
|
let activeMovieDetail = {
|
||||||
|
index: null,
|
||||||
|
sourceCard: null
|
||||||
|
};
|
||||||
|
|
||||||
const weekdayShort = ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"];
|
const weekdayShort = ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"];
|
||||||
|
|
||||||
@@ -437,6 +463,29 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getMovieDurationLabel = (movie) => {
|
||||||
|
const duration = movie?.duration ?? "";
|
||||||
|
return Number.isFinite(Number(duration)) ? `${duration} Min.` : escapeHtml(duration || "tba");
|
||||||
|
};
|
||||||
|
|
||||||
|
const getYoutubeVideoId = (input) => {
|
||||||
|
const value = String(input || "").trim();
|
||||||
|
if (!value) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const watchMatch = value.match(/[?&]v=([^&]+)/);
|
||||||
|
const shortMatch = value.match(/youtu\.be\/([^?&/]+)/);
|
||||||
|
const embedMatch = value.match(/embed\/([^?&/]+)/);
|
||||||
|
|
||||||
|
return decodeURIComponent(watchMatch?.[1] || shortMatch?.[1] || embedMatch?.[1] || value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getYoutubeThumbnailUrl = (videoId) => {
|
||||||
|
const id = getYoutubeVideoId(videoId);
|
||||||
|
return id ? `https://i.ytimg.com/vi/${encodeURIComponent(id)}/hqdefault.jpg` : "";
|
||||||
|
};
|
||||||
|
|
||||||
const formatDateShort = (dateObj) => {
|
const formatDateShort = (dateObj) => {
|
||||||
const day = String(dateObj.getDate()).padStart(2, "0");
|
const day = String(dateObj.getDate()).padStart(2, "0");
|
||||||
const month = String(dateObj.getMonth() + 1).padStart(2, "0");
|
const month = String(dateObj.getMonth() + 1).padStart(2, "0");
|
||||||
@@ -499,6 +548,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const buildMovieProgram = () => {
|
const buildMovieProgram = () => {
|
||||||
movieProgram = movieCatalog.map((movie, movieIndex) => ({
|
movieProgram = movieCatalog.map((movie, movieIndex) => ({
|
||||||
...movie,
|
...movie,
|
||||||
|
trailerYoutubeId: getYoutubeVideoId(movie.trailerYoutubeId || movie.trailerUrl || ""),
|
||||||
|
trailerThumbnail: getYoutubeThumbnailUrl(movie.trailerYoutubeId || movie.trailerUrl || "") || movie.backdrop || movie.poster,
|
||||||
|
actors: Array.isArray(movie.actors) ? movie.actors : [],
|
||||||
schedule: buildScheduleForMovie(movieIndex)
|
schedule: buildScheduleForMovie(movieIndex)
|
||||||
}));
|
}));
|
||||||
heroItems = movieProgram.slice(0, 5);
|
heroItems = movieProgram.slice(0, 5);
|
||||||
@@ -575,7 +627,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui.nowRunningRow.innerHTML = movieProgram.map((movie, index) => `
|
ui.nowRunningRow.innerHTML = movieProgram.map((movie, index) => `
|
||||||
<article class="running-poster">
|
<article class="running-poster" data-program-index="${index}" tabindex="0" role="button" aria-label="Details zu ${escapeHtml(movie.title)} öffnen">
|
||||||
<img src="${escapeHtml(movie.poster)}" alt="${escapeHtml(movie.title)}">
|
<img src="${escapeHtml(movie.poster)}" alt="${escapeHtml(movie.title)}">
|
||||||
<div class="running-meta">
|
<div class="running-meta">
|
||||||
<h4>${escapeHtml(movie.title)}</h4>
|
<h4>${escapeHtml(movie.title)}</h4>
|
||||||
@@ -637,7 +689,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
<div class="card-right">
|
<div class="card-right">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h2>${escapeHtml(movie.title)}</h2>
|
<h2>${escapeHtml(movie.title)}</h2>
|
||||||
<span class="duration movie-meta-line">${movie.duration} Min. | ${escapeHtml(movie.genre)} | FSK: ${renderFskMetaLogo(movie)}</span>
|
<span class="duration movie-meta-line">${getMovieDurationLabel(movie)} | ${escapeHtml(movie.genre)} | FSK: ${renderFskMetaLogo(movie)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="program-halls-summary">
|
<div class="program-halls-summary">
|
||||||
<strong>Kinosaal</strong>
|
<strong>Kinosaal</strong>
|
||||||
@@ -663,6 +715,169 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ensureMovieDetailOverlay = () => {
|
||||||
|
let overlay = document.getElementById("movie-detail-overlay");
|
||||||
|
if (overlay) {
|
||||||
|
return overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
overlay = document.createElement("div");
|
||||||
|
overlay.id = "movie-detail-overlay";
|
||||||
|
overlay.className = "movie-detail-overlay hidden";
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
return overlay;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderMovieDetailScheduleRows = (programIndex, dayIndex) => {
|
||||||
|
const movie = movieProgram[programIndex];
|
||||||
|
const day = movie?.schedule?.[dayIndex];
|
||||||
|
const body = document.getElementById("movie-detail-schedule-body");
|
||||||
|
if (!movie || !day || !body) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.innerHTML = day.showings.map((showing) => `
|
||||||
|
<button class="schedule-row time-chip program-time-row movie-detail-time-row" data-movie="${escapeHtml(movie.title)}" data-hall="${escapeHtml(showing.hall)}" data-time="${escapeHtml(showing.time)}">
|
||||||
|
<span>${escapeHtml(day.long)}</span>
|
||||||
|
<span class="hall-pill">${escapeHtml(showing.hall)}</span>
|
||||||
|
<span class="time-btn">${escapeHtml(showing.time)}</span>
|
||||||
|
</button>
|
||||||
|
`).join("");
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildMovieDetailContent = (movie, programIndex) => {
|
||||||
|
const trailerId = getYoutubeVideoId(movie.trailerYoutubeId);
|
||||||
|
const trailerThumb = getYoutubeThumbnailUrl(trailerId) || movie.backdrop || movie.poster;
|
||||||
|
const actorMarkup = movie.actors.length
|
||||||
|
? movie.actors.map((actor) => `<span>${escapeHtml(actor)}</span>`).join("")
|
||||||
|
: `<p>Noch keine Schauspieler hinterlegt.</p>`;
|
||||||
|
const dayTabs = movie.schedule.map((day, dayIndex) => `
|
||||||
|
<button type="button" class="program-day-tab movie-detail-day-tab ${dayIndex === 0 ? "active" : ""}" data-program-index="${programIndex}" data-day-index="${dayIndex}">
|
||||||
|
<span>${escapeHtml(day.short)}</span>
|
||||||
|
<small>${escapeHtml(formatDateShort(day.date))}</small>
|
||||||
|
</button>
|
||||||
|
`).join("");
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="movie-detail-stage">
|
||||||
|
<button type="button" class="movie-detail-close" aria-label="Filmdetails schließen">×</button>
|
||||||
|
<div class="movie-detail-backdrop" style="background-image: linear-gradient(180deg, rgba(4, 6, 10, 0.28), #05070a 78%), url('${escapeHtml(movie.backdrop || movie.poster)}');"></div>
|
||||||
|
<div class="movie-detail-content">
|
||||||
|
<section class="movie-detail-hero-block">
|
||||||
|
<div class="movie-detail-poster">
|
||||||
|
<img src="${escapeHtml(movie.poster)}" alt="${escapeHtml(movie.title)}">
|
||||||
|
</div>
|
||||||
|
<div class="movie-detail-copy">
|
||||||
|
<p class="movie-detail-kicker">Aktueller Film</p>
|
||||||
|
<h2>${escapeHtml(movie.title)}</h2>
|
||||||
|
<div class="movie-detail-meta movie-meta-line">
|
||||||
|
<span>${getMovieDurationLabel(movie)}</span>
|
||||||
|
<span>${escapeHtml(movie.genre)}</span>
|
||||||
|
${renderFskMetaLogo(movie)}
|
||||||
|
</div>
|
||||||
|
<p>${escapeHtml(movie.description)}</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="movie-detail-section">
|
||||||
|
<div class="movie-detail-section-head movie-detail-trailer-head">
|
||||||
|
<h3>Trailer</h3>
|
||||||
|
<span class="movie-detail-youtube-logo"><img src="img/youtube-logo.png" alt="YouTube Logo"></span>
|
||||||
|
</div>
|
||||||
|
<div class="movie-trailer-frame">
|
||||||
|
<button type="button" class="movie-trailer-preview" data-trailer-id="${escapeHtml(trailerId)}" style="background-image: linear-gradient(180deg, rgba(0,0,0,0.05), rgba(0,0,0,0.42)), url('${escapeHtml(trailerThumb)}');">
|
||||||
|
<span class="movie-trailer-play" aria-hidden="true"></span>
|
||||||
|
<strong>Trailer ansehen</strong>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="movie-detail-section">
|
||||||
|
<div class="movie-detail-section-head">
|
||||||
|
<h3>Schauspieler</h3>
|
||||||
|
<span>Cast</span>
|
||||||
|
</div>
|
||||||
|
<div class="movie-actor-list">${actorMarkup}</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="movie-detail-section movie-detail-schedule">
|
||||||
|
<div class="movie-detail-section-head">
|
||||||
|
<h3>Spielzeiten</h3>
|
||||||
|
<span>Nur für diesen Film</span>
|
||||||
|
</div>
|
||||||
|
<div class="program-day-tabs">${dayTabs}</div>
|
||||||
|
<div class="schedule-container program-schedule-shell">
|
||||||
|
<div class="schedule-header">
|
||||||
|
<span>Tag</span><span>Kinosaal</span><span>Uhrzeit</span>
|
||||||
|
</div>
|
||||||
|
<div id="movie-detail-schedule-body" class="program-schedule-body"></div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeMovieDetail = () => {
|
||||||
|
const overlay = document.getElementById("movie-detail-overlay");
|
||||||
|
if (!overlay || overlay.classList.contains("hidden")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetCard = activeMovieDetail.sourceCard?.isConnected ? activeMovieDetail.sourceCard : null;
|
||||||
|
const rect = targetCard?.getBoundingClientRect();
|
||||||
|
|
||||||
|
overlay.classList.remove("is-open");
|
||||||
|
overlay.classList.add("is-closing");
|
||||||
|
|
||||||
|
if (rect) {
|
||||||
|
overlay.style.left = `${rect.left}px`;
|
||||||
|
overlay.style.top = `${rect.top}px`;
|
||||||
|
overlay.style.width = `${rect.width}px`;
|
||||||
|
overlay.style.height = `${rect.height}px`;
|
||||||
|
overlay.style.borderRadius = getComputedStyle(targetCard).borderRadius || "20px";
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
overlay.className = "movie-detail-overlay hidden";
|
||||||
|
overlay.removeAttribute("style");
|
||||||
|
overlay.innerHTML = "";
|
||||||
|
document.body.style.overflow = "auto";
|
||||||
|
activeMovieDetail = { index: null, sourceCard: null };
|
||||||
|
}, 430);
|
||||||
|
};
|
||||||
|
|
||||||
|
const openMovieDetail = (programIndex, sourceCard) => {
|
||||||
|
const movie = movieProgram[programIndex];
|
||||||
|
if (!movie || !sourceCard) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const overlay = ensureMovieDetailOverlay();
|
||||||
|
const rect = sourceCard.getBoundingClientRect();
|
||||||
|
activeMovieDetail = { index: programIndex, sourceCard };
|
||||||
|
|
||||||
|
overlay.innerHTML = buildMovieDetailContent(movie, programIndex);
|
||||||
|
overlay.className = "movie-detail-overlay";
|
||||||
|
overlay.style.left = `${rect.left}px`;
|
||||||
|
overlay.style.top = `${rect.top}px`;
|
||||||
|
overlay.style.width = `${rect.width}px`;
|
||||||
|
overlay.style.height = `${rect.height}px`;
|
||||||
|
overlay.style.borderRadius = getComputedStyle(sourceCard).borderRadius || "20px";
|
||||||
|
document.body.style.overflow = "hidden";
|
||||||
|
|
||||||
|
renderMovieDetailScheduleRows(programIndex, 0);
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
overlay.classList.add("is-open");
|
||||||
|
overlay.style.left = "0px";
|
||||||
|
overlay.style.top = "0px";
|
||||||
|
overlay.style.width = "100vw";
|
||||||
|
overlay.style.height = "100vh";
|
||||||
|
overlay.style.borderRadius = "0px";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const initRevealAnimations = () => {
|
const initRevealAnimations = () => {
|
||||||
const revealElements = Array.from(document.querySelectorAll(".reveal-on-scroll"));
|
const revealElements = Array.from(document.querySelectorAll(".reveal-on-scroll"));
|
||||||
if (!revealElements.length) {
|
if (!revealElements.length) {
|
||||||
@@ -749,28 +964,107 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const bindProgramActions = () => {
|
const bindProgramActions = () => {
|
||||||
views.moviesGrid?.addEventListener("click", (event) => {
|
views.moviesGrid?.addEventListener("click", (event) => {
|
||||||
const trigger = event.target.closest(".open-program-btn");
|
const trigger = event.target.closest(".open-program-btn");
|
||||||
if (!trigger) {
|
if (trigger) {
|
||||||
|
const programIndex = Number(trigger.dataset.programIndex || 0);
|
||||||
|
showMovieList(programIndex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const programIndex = Number(trigger.dataset.programIndex || 0);
|
const runningCard = event.target.closest(".running-poster");
|
||||||
showMovieList(programIndex);
|
if (runningCard) {
|
||||||
|
const programIndex = Number(runningCard.dataset.programIndex || 0);
|
||||||
|
openMovieDetail(programIndex, runningCard);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
views.moviesGrid?.addEventListener("keydown", (event) => {
|
||||||
|
if (event.key !== "Enter" && event.key !== " ") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.target.closest(".open-program-btn")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const runningCard = event.target.closest(".running-poster");
|
||||||
|
if (!runningCard) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
const programIndex = Number(runningCard.dataset.programIndex || 0);
|
||||||
|
openMovieDetail(programIndex, runningCard);
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.movieProgramList?.addEventListener("click", (event) => {
|
ui.movieProgramList?.addEventListener("click", (event) => {
|
||||||
const dayButton = event.target.closest(".program-day-tab");
|
const dayButton = event.target.closest(".program-day-tab");
|
||||||
if (!dayButton) {
|
if (dayButton) {
|
||||||
|
const programIndex = Number(dayButton.dataset.programIndex || 0);
|
||||||
|
const dayIndex = Number(dayButton.dataset.dayIndex || 0);
|
||||||
|
|
||||||
|
const tabRow = dayButton.closest(".program-day-tabs");
|
||||||
|
tabRow?.querySelectorAll(".program-day-tab").forEach((tab) => tab.classList.remove("active"));
|
||||||
|
dayButton.classList.add("active");
|
||||||
|
|
||||||
|
renderScheduleRows(programIndex, dayIndex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const programIndex = Number(dayButton.dataset.programIndex || 0);
|
if (event.target.closest("button, a, input, select, textarea")) {
|
||||||
const dayIndex = Number(dayButton.dataset.dayIndex || 0);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const tabRow = dayButton.closest(".program-day-tabs");
|
const movieCard = event.target.closest(".program-card");
|
||||||
tabRow?.querySelectorAll(".program-day-tab").forEach((tab) => tab.classList.remove("active"));
|
if (!movieCard) {
|
||||||
dayButton.classList.add("active");
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
renderScheduleRows(programIndex, dayIndex);
|
const programIndex = Number(movieCard.dataset.programIndex || 0);
|
||||||
|
openMovieDetail(programIndex, movieCard);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const bindMovieDetailOverlay = () => {
|
||||||
|
document.addEventListener("click", (event) => {
|
||||||
|
const overlay = event.target.closest("#movie-detail-overlay");
|
||||||
|
if (!overlay) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.target.closest(".movie-detail-close")) {
|
||||||
|
closeMovieDetail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dayButton = event.target.closest(".movie-detail-day-tab");
|
||||||
|
if (dayButton) {
|
||||||
|
const dayIndex = Number(dayButton.dataset.dayIndex || 0);
|
||||||
|
overlay.querySelectorAll(".movie-detail-day-tab").forEach((tab) => tab.classList.remove("active"));
|
||||||
|
dayButton.classList.add("active");
|
||||||
|
renderMovieDetailScheduleRows(activeMovieDetail.index, dayIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const trailerPreview = event.target.closest(".movie-trailer-preview");
|
||||||
|
if (trailerPreview) {
|
||||||
|
const trailerId = getYoutubeVideoId(trailerPreview.dataset.trailerId);
|
||||||
|
const frame = trailerPreview.closest(".movie-trailer-frame");
|
||||||
|
if (!trailerId || !frame) {
|
||||||
|
trailerPreview.classList.add("is-missing");
|
||||||
|
trailerPreview.querySelector("strong").textContent = "Trailer-ID in main.js hinterlegen";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.innerHTML = `
|
||||||
|
<iframe src="https://www.youtube-nocookie.com/embed/${encodeURIComponent(trailerId)}?autoplay=1&rel=0" title="YouTube Trailer" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("keydown", (event) => {
|
||||||
|
if (event.key === "Escape") {
|
||||||
|
closeMovieDetail();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -872,6 +1166,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const loginEmailInput = document.getElementById("login-email");
|
const loginEmailInput = document.getElementById("login-email");
|
||||||
const loginPasswordInput = document.getElementById("login-password");
|
const loginPasswordInput = document.getElementById("login-password");
|
||||||
|
|
||||||
|
if (typeof initAccountFieldValidation === "function") {
|
||||||
|
initAccountFieldValidation();
|
||||||
|
}
|
||||||
|
|
||||||
const openModal = (modal) => modal?.classList.remove("hidden");
|
const openModal = (modal) => modal?.classList.remove("hidden");
|
||||||
const closeModal = (modal) => modal?.classList.add("hidden");
|
const closeModal = (modal) => modal?.classList.add("hidden");
|
||||||
const triggerLogin = () => {
|
const triggerLogin = () => {
|
||||||
@@ -882,6 +1180,24 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
document.getElementById("btn-open-register")?.addEventListener("click", () => {
|
document.getElementById("btn-open-register")?.addEventListener("click", () => {
|
||||||
|
registerModal?.querySelectorAll("input, select").forEach((input) => {
|
||||||
|
if (input.type !== "hidden" && input.tagName !== "SELECT") {
|
||||||
|
input.value = "";
|
||||||
|
}
|
||||||
|
if (input.tagName === "SELECT") {
|
||||||
|
input.value = "Deutschland";
|
||||||
|
}
|
||||||
|
if (input.id === "reg-salutation") {
|
||||||
|
input.value = "";
|
||||||
|
}
|
||||||
|
input.dataset.touched = "";
|
||||||
|
if (typeof clearFieldError === "function") {
|
||||||
|
clearFieldError(input);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
registerModal?.querySelectorAll(".gender-selector button").forEach((button) => {
|
||||||
|
button.classList.remove("active");
|
||||||
|
});
|
||||||
openModal(registerModal);
|
openModal(registerModal);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -898,6 +1214,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
document.getElementById("btn-login-account")?.addEventListener("click", triggerLogin);
|
document.getElementById("btn-login-account")?.addEventListener("click", triggerLogin);
|
||||||
|
|
||||||
[loginEmailInput, loginPasswordInput].forEach((input) => {
|
[loginEmailInput, loginPasswordInput].forEach((input) => {
|
||||||
|
input?.addEventListener("input", () => {
|
||||||
|
loginError?.classList.add("hidden");
|
||||||
|
});
|
||||||
|
|
||||||
input?.addEventListener("keydown", (event) => {
|
input?.addEventListener("keydown", (event) => {
|
||||||
if (event.key !== "Enter") {
|
if (event.key !== "Enter") {
|
||||||
return;
|
return;
|
||||||
@@ -1134,6 +1454,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
initThemeToggle();
|
initThemeToggle();
|
||||||
bindNavigation();
|
bindNavigation();
|
||||||
bindProgramActions();
|
bindProgramActions();
|
||||||
|
bindMovieDetailOverlay();
|
||||||
bindHomeInfoNavigation();
|
bindHomeInfoNavigation();
|
||||||
bindAccountActions();
|
bindAccountActions();
|
||||||
bindGlobalDocumentClicks();
|
bindGlobalDocumentClicks();
|
||||||
|
|||||||
721
style.css
721
style.css
@@ -4844,3 +4844,724 @@ body.theme-light .limited-special-card.wide-special .snack-img img {
|
|||||||
min-height: 176px;
|
min-height: 176px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- Account registration form refresh --- */
|
||||||
|
.auth-field {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-field input,
|
||||||
|
.auth-field select {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-field .field-error {
|
||||||
|
min-height: 16px;
|
||||||
|
display: block;
|
||||||
|
margin-top: 5px;
|
||||||
|
color: #ff6d7d;
|
||||||
|
font-size: 0.76rem;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-field.is-invalid input,
|
||||||
|
.auth-field.is-invalid select,
|
||||||
|
.auth-field.is-invalid .gender-selector {
|
||||||
|
border-color: rgba(255, 84, 105, 0.88) !important;
|
||||||
|
box-shadow: 0 0 0 3px rgba(255, 84, 105, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
#login-error {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
padding: 9px 11px;
|
||||||
|
border: 1px solid rgba(255, 84, 105, 0.35);
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(255, 84, 105, 0.1);
|
||||||
|
color: #ff8795;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-auth-modal {
|
||||||
|
width: min(1180px, 94vw);
|
||||||
|
max-width: 1180px;
|
||||||
|
max-height: 88vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 28px 30px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||||
|
gap: 22px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form-section {
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
background: rgba(255, 255, 255, 0.035);
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form-section h3 {
|
||||||
|
margin-bottom: 14px;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: #f7faff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form-section input,
|
||||||
|
.register-form-section select {
|
||||||
|
min-height: 48px;
|
||||||
|
border-width: 0 0 1px;
|
||||||
|
border-radius: 0;
|
||||||
|
background: transparent;
|
||||||
|
padding: 10px 2px;
|
||||||
|
color: #f5f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form-section select {
|
||||||
|
appearance: none;
|
||||||
|
background-image: linear-gradient(45deg, transparent 50%, #9aa7ba 50%), linear-gradient(135deg, #9aa7ba 50%, transparent 50%);
|
||||||
|
background-position: calc(100% - 18px) 21px, calc(100% - 12px) 21px;
|
||||||
|
background-size: 6px 6px, 6px 6px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.street-row {
|
||||||
|
grid-template-columns: minmax(0, 1fr) 110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gender-selector {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.16);
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gender-selector button {
|
||||||
|
min-height: 52px;
|
||||||
|
border: 0;
|
||||||
|
border-right: 1px solid rgba(255, 255, 255, 0.16);
|
||||||
|
background: transparent;
|
||||||
|
color: #f8fbff;
|
||||||
|
font-weight: 700;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gender-selector button:last-child {
|
||||||
|
border-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gender-selector button.active {
|
||||||
|
background: rgba(0, 113, 227, 0.28);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-warning {
|
||||||
|
color: #8f98a7;
|
||||||
|
font-size: 0.84rem;
|
||||||
|
line-height: 1.45;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-personal-card h3 {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-personal-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-personal-grid p {
|
||||||
|
margin: 0;
|
||||||
|
padding: 11px 12px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(255, 255, 255, 0.035);
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-personal-grid span {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
color: #91a0b4;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-personal-grid strong {
|
||||||
|
color: #f6f9ff;
|
||||||
|
font-size: 0.92rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .auth-field.is-invalid input,
|
||||||
|
body.theme-light .auth-field.is-invalid select,
|
||||||
|
body.theme-light .auth-field.is-invalid .gender-selector {
|
||||||
|
border-color: rgba(216, 42, 66, 0.82) !important;
|
||||||
|
box-shadow: 0 0 0 3px rgba(216, 42, 66, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .register-form-section {
|
||||||
|
background: #f7faff;
|
||||||
|
border-color: rgba(28, 56, 94, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .register-form-section h3 {
|
||||||
|
color: #10213a;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .register-form-section input,
|
||||||
|
body.theme-light .register-form-section select {
|
||||||
|
background: transparent !important;
|
||||||
|
color: #10213a !important;
|
||||||
|
border-color: rgba(33, 55, 91, 0.22) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .gender-selector {
|
||||||
|
background: #eef4ff;
|
||||||
|
border-color: rgba(28, 56, 94, 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .gender-selector button {
|
||||||
|
color: #1b2f4d;
|
||||||
|
border-color: rgba(28, 56, 94, 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .gender-selector button.active {
|
||||||
|
background: #dcecff;
|
||||||
|
color: #0057ae;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .register-warning {
|
||||||
|
color: #5a6c86;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .account-personal-grid p {
|
||||||
|
background: #f7faff;
|
||||||
|
border-color: rgba(28, 56, 94, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .account-personal-grid span {
|
||||||
|
color: #52647f;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .account-personal-grid strong {
|
||||||
|
color: #10213a;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .auth-field.is-invalid input,
|
||||||
|
body.theme-light .auth-field.is-invalid select,
|
||||||
|
body.theme-light .auth-field.is-invalid .gender-selector,
|
||||||
|
body.theme-light .register-form-section .auth-field.is-invalid input,
|
||||||
|
body.theme-light .register-form-section .auth-field.is-invalid select {
|
||||||
|
border-color: rgba(216, 42, 66, 0.82) !important;
|
||||||
|
box-shadow: 0 0 0 3px rgba(216, 42, 66, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 860px) {
|
||||||
|
.register-form-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-auth-modal {
|
||||||
|
padding: 24px 18px 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 560px) {
|
||||||
|
.register-row,
|
||||||
|
.street-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Account edit and movie detail overlay --- */
|
||||||
|
.account-header-actions {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-edit-btn {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
color: #ffffff;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-edit-btn:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
border-color: rgba(0, 113, 227, 0.75);
|
||||||
|
background: rgba(0, 113, 227, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-edit-btn svg {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
fill: none;
|
||||||
|
stroke: currentColor;
|
||||||
|
stroke-width: 2;
|
||||||
|
stroke-linecap: round;
|
||||||
|
stroke-linejoin: round;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-card-title-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-card-title-row h3 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-card-title-row span {
|
||||||
|
color: #8fa0b6;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-edit-form {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
|
||||||
|
gap: 12px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-edit-form .auth-field {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-edit-form .auth-field > span:first-child,
|
||||||
|
.account-email-locked > span:first-child {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
color: #91a0b4;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-edit-form input,
|
||||||
|
.account-edit-form select {
|
||||||
|
min-height: 46px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
color: #f6f9ff;
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-email-locked input:disabled {
|
||||||
|
opacity: 0.72;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-email-locked small {
|
||||||
|
display: block;
|
||||||
|
margin-top: 6px;
|
||||||
|
color: #7e8da1;
|
||||||
|
font-size: 0.74rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-edit-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-save-btn,
|
||||||
|
.account-secondary-btn {
|
||||||
|
border: 0;
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
font-weight: 800;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-save-btn {
|
||||||
|
background: #0071e3;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-secondary-btn {
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.program-card,
|
||||||
|
.running-poster {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.program-card:focus-within,
|
||||||
|
.running-poster:focus-visible {
|
||||||
|
outline: 2px solid rgba(0, 113, 227, 0.8);
|
||||||
|
outline-offset: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-overlay {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 10000;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #05070a;
|
||||||
|
box-shadow: 0 30px 90px rgba(0, 0, 0, 0.5);
|
||||||
|
transition: left 0.46s cubic-bezier(0.2, 0.82, 0.2, 1),
|
||||||
|
top 0.46s cubic-bezier(0.2, 0.82, 0.2, 1),
|
||||||
|
width 0.46s cubic-bezier(0.2, 0.82, 0.2, 1),
|
||||||
|
height 0.46s cubic-bezier(0.2, 0.82, 0.2, 1),
|
||||||
|
border-radius 0.46s cubic-bezier(0.2, 0.82, 0.2, 1),
|
||||||
|
opacity 0.28s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-overlay.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-overlay.is-closing {
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-stage {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.985);
|
||||||
|
transition: opacity 0.25s ease 0.12s, transform 0.32s ease 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-overlay.is-open .movie-detail-stage {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-backdrop {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0 0 auto;
|
||||||
|
height: min(620px, 76vh);
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
filter: saturate(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-content {
|
||||||
|
position: relative;
|
||||||
|
width: min(1180px, calc(100% - 32px));
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 112px 0 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-close {
|
||||||
|
position: fixed;
|
||||||
|
top: 22px;
|
||||||
|
right: 24px;
|
||||||
|
z-index: 2;
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(12, 14, 18, 0.76);
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
backdrop-filter: blur(18px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-hero-block {
|
||||||
|
min-height: 520px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(190px, 300px) minmax(0, 1fr);
|
||||||
|
align-items: end;
|
||||||
|
gap: clamp(24px, 5vw, 58px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-poster img {
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 2 / 3;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 28px 70px rgba(0, 0, 0, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-copy {
|
||||||
|
padding-bottom: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-kicker {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #9bc8ff;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 800;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-copy h2 {
|
||||||
|
max-width: 820px;
|
||||||
|
margin: 0 0 14px;
|
||||||
|
font-size: clamp(2.1rem, 5vw, 5.2rem);
|
||||||
|
line-height: 0.96;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-meta {
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
color: #dce7f6;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-copy > p:last-child {
|
||||||
|
max-width: 760px;
|
||||||
|
color: #d5dbe5;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-section {
|
||||||
|
margin-top: 28px;
|
||||||
|
padding-top: 28px;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-section-head {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-section-head h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-section-head span {
|
||||||
|
color: #8d98a8;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
font-weight: 800;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-youtube-logo {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-youtube-logo img {
|
||||||
|
width: 34px;
|
||||||
|
max-height: 18px;
|
||||||
|
object-fit: contain;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-trailer-frame {
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
width: min(920px, 100%);
|
||||||
|
background: #0b0d11;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-trailer-preview {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
align-content: center;
|
||||||
|
gap: 14px;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
color: #ffffff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-trailer-preview strong {
|
||||||
|
text-shadow: 0 2px 18px rgba(0, 0, 0, 0.78);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-trailer-preview.is-missing {
|
||||||
|
filter: grayscale(0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-trailer-play {
|
||||||
|
width: 74px;
|
||||||
|
height: 74px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255, 255, 255, 0.92);
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-trailer-play::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 30px;
|
||||||
|
top: 23px;
|
||||||
|
border-top: 14px solid transparent;
|
||||||
|
border-bottom: 14px solid transparent;
|
||||||
|
border-left: 20px solid #0a0d12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-trailer-frame iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-actor-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-actor-list span {
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
color: #eef4ff;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-actor-list p {
|
||||||
|
margin: 0;
|
||||||
|
color: #8f9caf;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-schedule {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-time-row:hover {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .account-edit-btn,
|
||||||
|
body.theme-light .account-secondary-btn {
|
||||||
|
background: #eef4ff;
|
||||||
|
border-color: rgba(28, 56, 94, 0.16);
|
||||||
|
color: #10213a;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .account-card-title-row span,
|
||||||
|
body.theme-light .account-edit-form .auth-field > span:first-child,
|
||||||
|
body.theme-light .account-email-locked > span:first-child,
|
||||||
|
body.theme-light .account-email-locked small {
|
||||||
|
color: #52647f;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .account-edit-form input,
|
||||||
|
body.theme-light .account-edit-form select {
|
||||||
|
background: #ffffff;
|
||||||
|
border-color: rgba(28, 56, 94, 0.16);
|
||||||
|
color: #10213a;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .movie-detail-overlay {
|
||||||
|
background: #f4f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .movie-detail-backdrop {
|
||||||
|
filter: saturate(1.05) brightness(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .movie-detail-copy > p:last-child,
|
||||||
|
body.theme-light .movie-detail-meta,
|
||||||
|
body.theme-light .movie-actor-list span {
|
||||||
|
color: #10213a;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .movie-detail-copy h2,
|
||||||
|
body.theme-light .movie-detail-copy > p:last-child,
|
||||||
|
body.theme-light .movie-detail-meta {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .movie-detail-section {
|
||||||
|
border-color: rgba(28, 56, 94, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.theme-light .movie-actor-list span {
|
||||||
|
background: #ffffff;
|
||||||
|
border-color: rgba(28, 56, 94, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 760px) {
|
||||||
|
.account-panel-header,
|
||||||
|
.account-card-title-row {
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-edit-actions {
|
||||||
|
justify-content: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-save-btn,
|
||||||
|
.account-secondary-btn {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-content {
|
||||||
|
width: min(100% - 24px, 560px);
|
||||||
|
padding-top: 78px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-hero-block {
|
||||||
|
min-height: auto;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-poster {
|
||||||
|
width: min(210px, 62vw);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-copy {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-copy h2 {
|
||||||
|
font-size: clamp(2rem, 12vw, 3.8rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-section-head {
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-detail-trailer-head {
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-trailer-frame {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user