Create static visual facelift restore point

This commit is contained in:
nick 2026-07-31 19:35:55 +01:00
parent 0c14806520
commit 3262923f91
17 changed files with 824 additions and 483 deletions

View File

@ -38,31 +38,17 @@
<div class="col-lg-7 d-flex">
<div class="card character-card h-100 flex-fill" id="hero-media-card">
<div class="card-body d-flex flex-column">
<!-- Trailer -->
<div class="trailer-wrapper mb-3">
<!-- Desktop: LANDSCAPE -->
<video id="trailerLandscape"
class="w-100"
playsinline
preload="none"
poster="/images/webp/the-alpha-flame-discovery-trailer-landscape-1400.webp"
controls>
<source src="/videos/the-alpha-flame-discovery-trailer-landscape.mp4" type="video/mp4">
Sorry, your browser doesn't support embedded video.
</video>
<button id="trailerPlayBtn" class="trailer-play-btn">
<a asp-controller="Discovery" asp-action="Trailer" class="cl-trailer-still mb-3">
<responsive-image src="the-alpha-flame-discovery-trailer-landscape.png"
class="cl-trailer-still__image"
alt="The Alpha Flame: Discovery trailer still"
display-width-percentage="50"></responsive-image>
<span class="cl-trailer-still__veil"></span>
<span class="cl-trailer-still__button">
<i class="fad fa-play"></i>
</button>
</div>
<!-- If JS is off, hide the custom play button so native controls are used -->
<noscript>
<style>
#trailerPlayBtn {
display: none !important
}</style>
</noscript>
<span>Watch the trailer</span>
</span>
</a>
@await Component.InvokeAsync("BuyPanel", new { ISO2 = Model.UserIso2, Src = Model.Src, Title = Model.Title })
@ -264,48 +250,6 @@
const player = new Plyr('audio');
</script>
<!-- Trailer play/pause via custom button or video click (desktop only) -->
<script>
document.addEventListener("DOMContentLoaded", () => {
const v = document.getElementById("trailerLandscape");
const playBtn = document.getElementById("trailerPlayBtn");
if (!v || !playBtn) return;
// Hide native controls when JS is active; use custom button instead
v.controls = false;
// Start playback
const startPlayback = () => {
v.muted = false;
v.volume = 1.0;
v.play()
.then(() => { playBtn.style.display = "none"; })
.catch(err => console.warn("Video play failed:", err));
};
// Toggle on video click
const togglePlayback = () => {
if (v.paused) {
startPlayback();
} else {
v.pause();
playBtn.style.display = "block";
}
};
// Events
playBtn.addEventListener("click", (e) => { e.preventDefault(); startPlayback(); });
v.addEventListener("click", togglePlayback);
// Keep button state in sync with native events
v.addEventListener("play", () => { playBtn.style.display = "none"; });
v.addEventListener("pause", () => { playBtn.style.display = "block"; });
v.addEventListener("ended", () => { playBtn.style.display = "block"; });
});
</script>
<script>
document.addEventListener('DOMContentLoaded', function () {
const el = document.getElementById('fullSynopsis');

View File

@ -30,31 +30,17 @@
<div class="col-12">
<div class="card character-card" id="hero-media-card">
<div class="card-body">
<!-- Trailer -->
<div class="trailer-wrapper mb-3">
<!-- Mobile / tablet: PORTRAIT -->
<video id="trailerPortrait"
class="w-100"
playsinline
preload="none"
poster="/images/webp/the-alpha-flame-discovery-trailer-portrait-400.webp"
controls>
<source src="/videos/the-alpha-flame-discovery-trailer-portrait.mp4" type="video/mp4">
Sorry, your browser doesn't support embedded video.
</video>
<button id="trailerPlayBtn" class="trailer-play-btn">
<a asp-controller="Discovery" asp-action="Trailer" class="cl-trailer-still cl-trailer-still--portrait mb-3">
<responsive-image src="the-alpha-flame-discovery-trailer-portrait.png"
class="cl-trailer-still__image"
alt="The Alpha Flame: Discovery trailer still"
display-width-percentage="50"></responsive-image>
<span class="cl-trailer-still__veil"></span>
<span class="cl-trailer-still__button">
<i class="fad fa-play"></i>
</button>
</div>
<!-- If JS is off, hide the custom play button so native controls are used -->
<noscript>
<style>
#trailerPlayBtn {
display: none !important
}</style>
</noscript>
<span>Watch the trailer</span>
</span>
</a>
@await Component.InvokeAsync("BuyPanel", new { ISO2 = Model.UserIso2, Src = Model.Src })
@ -243,47 +229,6 @@
const player = new Plyr('audio');
</script>
<!-- Trailer play/pause via custom button or video click (single video) -->
<script>
document.addEventListener("DOMContentLoaded", () => {
const v = document.getElementById("trailerPortrait");
const playBtn = document.getElementById("trailerPlayBtn");
if (!v || !playBtn) return;
// Hide native controls when JS is active; use custom button instead
v.controls = false;
// Start playback
const startPlayback = () => {
v.muted = false;
v.volume = 1.0;
v.play()
.then(() => { playBtn.style.display = "none"; })
.catch(err => console.warn("Video play failed:", err));
};
// Toggle on video click
const togglePlayback = () => {
if (v.paused) {
startPlayback();
} else {
v.pause();
playBtn.style.display = "block";
}
};
// Events
playBtn.addEventListener("click", (e) => { e.preventDefault(); startPlayback(); });
v.addEventListener("click", togglePlayback);
// Keep button state in sync with native events
v.addEventListener("play", () => { playBtn.style.display = "none"; });
v.addEventListener("pause", () => { playBtn.style.display = "block"; });
v.addEventListener("ended", () => { playBtn.style.display = "block"; });
});
</script>
}
@section Meta {

View File

@ -24,31 +24,17 @@
<div class="col-12">
<div class="card character-card" id="hero-media-card">
<div class="card-body">
<!-- Trailer -->
<div class="trailer-wrapper mb-3">
<!-- Mobile / tablet: PORTRAIT -->
<video id="trailerPortrait"
class="w-100"
playsinline
preload="none"
poster="/images/webp/the-alpha-flame-discovery-trailer-portrait-400.webp"
controls>
<source src="/videos/the-alpha-flame-discovery-trailer-portrait.mp4" type="video/mp4">
Sorry, your browser doesn't support embedded video.
</video>
<button id="trailerPlayBtn" class="trailer-play-btn">
<a asp-controller="Discovery" asp-action="Trailer" class="cl-trailer-still cl-trailer-still--portrait mb-3">
<responsive-image src="the-alpha-flame-discovery-trailer-portrait.png"
class="cl-trailer-still__image"
alt="The Alpha Flame: Discovery trailer still"
display-width-percentage="50"></responsive-image>
<span class="cl-trailer-still__veil"></span>
<span class="cl-trailer-still__button">
<i class="fad fa-play"></i>
</button>
</div>
<!-- If JS is off, hide the custom play button so native controls are used -->
<noscript>
<style>
#trailerPlayBtn {
display: none !important
}</style>
</noscript>
<span>Watch the trailer</span>
</span>
</a>
</div>
</div>
</div>
@ -244,47 +230,6 @@
const player = new Plyr('audio');
</script>
<!-- Trailer play/pause via custom button or video click (single video) -->
<script>
document.addEventListener("DOMContentLoaded", () => {
const v = document.getElementById("trailerPortrait");
const playBtn = document.getElementById("trailerPlayBtn");
if (!v || !playBtn) return;
// Hide native controls when JS is active; use custom button instead
v.controls = false;
// Start playback
const startPlayback = () => {
v.muted = false;
v.volume = 1.0;
v.play()
.then(() => { playBtn.style.display = "none"; })
.catch(err => console.warn("Video play failed:", err));
};
// Toggle on video click
const togglePlayback = () => {
if (v.paused) {
startPlayback();
} else {
v.pause();
playBtn.style.display = "block";
}
};
// Events
playBtn.addEventListener("click", (e) => { e.preventDefault(); startPlayback(); });
v.addEventListener("click", togglePlayback);
// Keep button state in sync with native events
v.addEventListener("play", () => { playBtn.style.display = "none"; });
v.addEventListener("pause", () => { playBtn.style.display = "block"; });
v.addEventListener("ended", () => { playBtn.style.display = "block"; });
});
</script>
}
@section Meta {

View File

@ -2,36 +2,10 @@
Layout = "/Views/Shared/_Layout.cshtml";
}
@section CSS {
<style>
.video-overlay {
background-color: rgba(13, 202, 240, 0.2);
}
</style>
}
@section Meta {
@RenderSection("Meta", required: false)
}
@section BackgroundVideo {
<div id="background-wrapper">
<div class="video-background">
<video id="siteBackgroundVideo"
autoplay
muted
loop
playsinline
preload="none">
<!-- Source will be injected by JS -->
</video>
<div class="video-overlay"></div>
</div>
</div>
}
@RenderBody()
@section Scripts {

View File

@ -14,15 +14,19 @@
</div>
<div class="row">
<div class="col-12">
<div class="cl-editorial-hero">
<p class="cl-kicker mb-2">About the author</p>
<h1 class="display-4 mb-3">Catherine Lynwood</h1>
<p class="lead mb-0">
Birmingham-born author of gritty, emotionally truthful fiction about women, survival, family secrets, and the fire people carry after everything else has been stripped away.
</p>
</div>
<div class="float-md-start w-md-50 p-3">
<figure>
<responsive-image src="catherine-lynwood-15.png" alt="Catherine Lynwood" class="img-fluid rounded-5 border border-3 border-dark shadow-lg" display-width-percentage="50"></responsive-image>
<figcaption>Catherine Lynwood</figcaption>
</figure>
</div>
<header>
<h1>About Catherine Lynwood</h1>
</header>
<section>
<p>Catherine Lynwood was born in Birmingham in 1979, growing up amidst the urban landscapes and industrial heritage of Britain’s second city. Raised in Rubery, Catherine was drawn to the arts from an early age, finding creative inspiration in the sights, sounds, and stories around her. She attended Colmers Farm School, where teachers quickly recognized her talent for drawing and storytelling, often encouraging her to explore her creativity in school projects and art classes.</p>

View File

@ -12,31 +12,39 @@
</div>
</div>
<div class="cl-editorial-hero">
<p class="cl-kicker mb-2">Gritty British drama by Catherine Lynwood</p>
<h1 class="display-4 mb-3">
Truthful stories about women, survival, and the secrets polite society leaves untouched.
</h1>
<p class="lead mb-0">
Character-led fiction rooted in emotional realism, Birmingham grit, family wounds, loyalty, fire, and the hard-won beauty of refusing to be broken.
</p>
</div>
<div class="row justify-content-center align-items-center mb-5">
<div class="col-md-5 text-center">
<a asp-controller="Reckoning" asp-action="Index">
<div class="hero-video-container">
<video id="heroVideo" autoplay muted loop playsinline preload="none" poster="/images/webp/the-alpha-flame-reckoning-400.webp">
<!-- Source will be injected later -->
</video>
<!-- Overlay image remains untouched -->
<responsive-image src="the-alpha-flame-reckoning-overlay.png"
class="hero-overlay-image"
alt="The Alpha Flame: Discovery by Catherine Lynwood"
display-width-percentage="50"
no-index="true">
</responsive-image>
<div class="cl-cover-feature">
<responsive-image src="the-alpha-flame-reckoning-cover.png"
class="cl-cover-feature__image"
alt="The Alpha Flame: Reckoning by Catherine Lynwood"
display-width-percentage="50"></responsive-image>
<div class="cl-cover-feature__label">
<span>The Alpha Flame</span>
<strong>Reckoning</strong>
</div>
</div>
</a>
</div>
<div class="col-md-7 pt-2 pt-md-0">
<h1 class="display-5 fw-bold">
<p class="cl-kicker mb-2">The Alpha Flame trilogy</p>
<h2 class="display-5 fw-bold">
The Alpha Flame
<span class="fw-light d-block fs-4">A Trilogy by Catherine Lynwood</span>
</h1>
</h2>
<p class="lead fst-italic tagline-shadow">
Some girls survive. Others set the world on fire.
@ -105,7 +113,7 @@
}
<p class="mt-4">
<h3 class="h6 d-inline"><em>About the Trilogy</em></h3>
<h3 class="h6 d-inline"><em>About the Trilogy</em></h3>&nbsp;
Set in 1980s Birmingham, <em>The Alpha Flame</em> blends family drama, emotional suspense,
and dark secrets rooted in real places and lived experience.
Ideal for readers who value character-driven storytelling, moral complexity,
@ -240,20 +248,4 @@
}
</script>
<script>
window.addEventListener("load", () => {
setTimeout(() => {
const video = document.getElementById("heroVideo");
const source = document.createElement("source");
source.src = "/videos/the-alpha-flame-reckoning.mp4";
source.type = "video/mp4";
video.appendChild(source);
video.load(); // Triggers actual file load
video.play().catch(err => {
console.warn("Autoplay failed:", err);
});
}, 2000); // Adjust delay (e.g., 1000–3000ms) based on your needs
});
</script>
}

View File

@ -5,7 +5,7 @@
<div class="container py-5">
<div class="row justify-content-center mb-5">
<div class="col-12 col-xl-10">
<div class="bg-dark rounded-4 p-4 p-md-5 shadow-sm border">
<div class="bg-dark rounded-4 p-4 p-md-5 shadow-sm border cl-editorial-hero">
<span class="badge text-bg-dark mb-3">Indie Author Guide</span>
<h1 class="display-5 fw-bold mb-3">Indie Author and Self-Publishing</h1>
<p class="lead mb-3">
@ -27,7 +27,7 @@
<div class="col-12 col-xl-10">
<div class="row g-4">
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm rounded-4">
<div class="card h-100 border-0 shadow-sm rounded-4 cl-feature-card">
<div class="card-body p-4">
<h2 class="h5 fw-bold mb-3">Traditional vs Self-Publishing</h2>
<p class="text-muted mb-4">
@ -42,7 +42,7 @@
</div>
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm rounded-4">
<div class="card h-100 border-0 shadow-sm rounded-4 cl-feature-card">
<div class="card-body p-4">
<h2 class="h5 fw-bold mb-3">ISBNs</h2>
<p class="text-muted mb-4">
@ -57,7 +57,7 @@
</div>
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm rounded-4">
<div class="card h-100 border-0 shadow-sm rounded-4 cl-feature-card">
<div class="card-body p-4">
<h2 class="h5 fw-bold mb-3">Editing and Proofreading</h2>
<p class="text-muted mb-4">
@ -72,7 +72,7 @@
</div>
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm rounded-4">
<div class="card h-100 border-0 shadow-sm rounded-4 cl-feature-card">
<div class="card-body p-4">
<h2 class="h5 fw-bold mb-3">Cover Design</h2>
<p class="text-muted mb-4">
@ -87,7 +87,7 @@
</div>
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm rounded-4">
<div class="card h-100 border-0 shadow-sm rounded-4 cl-feature-card">
<div class="card-body p-4">
<h2 class="h5 fw-bold mb-3">KDP vs IngramSpark</h2>
<p class="text-muted mb-4">
@ -102,7 +102,7 @@
</div>
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm rounded-4">
<div class="card h-100 border-0 shadow-sm rounded-4 cl-feature-card">
<div class="card-body p-4">
<h2 class="h5 fw-bold mb-3">Publishing on KDP</h2>
<p class="text-muted mb-4">
@ -117,7 +117,7 @@
</div>
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm rounded-4">
<div class="card h-100 border-0 shadow-sm rounded-4 cl-feature-card">
<div class="card-body p-4">
<h2 class="h5 fw-bold mb-3">Publishing on IngramSpark</h2>
<p class="text-muted mb-4">
@ -132,7 +132,7 @@
</div>
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm rounded-4">
<div class="card h-100 border-0 shadow-sm rounded-4 cl-feature-card">
<div class="card-body p-4">
<h2 class="h5 fw-bold mb-3">Audiobooks and ACX</h2>
<p class="text-muted mb-4">
@ -147,7 +147,7 @@
</div>
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm rounded-4">
<div class="card h-100 border-0 shadow-sm rounded-4 cl-feature-card">
<div class="card-body p-4">
<h2 class="h5 fw-bold mb-3">Reviews and ARC Readers</h2>
<p class="text-muted mb-4">
@ -162,7 +162,7 @@
</div>
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm rounded-4">
<div class="card h-100 border-0 shadow-sm rounded-4 cl-feature-card">
<div class="card-body p-4">
<h2 class="h5 fw-bold mb-3">Amazon Advertising</h2>
<p class="text-muted mb-4">
@ -177,7 +177,7 @@
</div>
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm rounded-4">
<div class="card h-100 border-0 shadow-sm rounded-4 cl-feature-card">
<div class="card-body p-4">
<h2 class="h5 fw-bold mb-3">Author Finances</h2>
<p class="text-muted mb-4">
@ -192,7 +192,7 @@
</div>
<div class="col-md-6 col-lg-4">
<div class="card h-100 border-0 shadow-sm rounded-4">
<div class="card h-100 border-0 shadow-sm rounded-4 cl-feature-card">
<div class="card-body p-4">
<h2 class="h5 fw-bold mb-3">AI for Authors</h2>
<p class="text-muted mb-4">

View File

@ -16,25 +16,6 @@
@RenderSection("BackgroundVideo", required: false)
}
}
else
{
@section BackgroundVideo {
<div id="background-wrapper">
<div class="video-background">
<video id="siteBackgroundVideo"
autoplay
muted
loop
playsinline
preload="none">
<!-- Source will be injected by JS -->
</video>
<div class="video-overlay"></div>
</div>
</div>
}
}
@RenderBody()
@section Scripts {

View File

@ -1,4 +1,18 @@
<!DOCTYPE html>
@{
var requestPath = Context.Request.Path.Value?.ToLowerInvariant() ?? "/";
var pageTone = requestPath.Contains("/the-alpha-flame/discovery")
? "cl-page-discovery"
: requestPath.Contains("/reckoning")
? "cl-page-reckoning"
: requestPath.Contains("/indie-author")
? "cl-page-guide"
: requestPath.Contains("/the-alpha-flame/blog")
? "cl-page-journal"
: requestPath == "/" || requestPath == ""
? "cl-page-home"
: "cl-page-general";
}
<!DOCTYPE html>
<html lang="en-GB">
<head>
<meta charset="utf-8" />
@ -43,9 +57,9 @@
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#17C8EB">
<meta name="msapplication-TileColor" content="#4B243A">
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
<meta name="theme-color" content="#17C8EB">
<meta name="theme-color" content="#181514">
@ -57,7 +71,7 @@
@RenderSection("Meta", required: false)
</head>
<body class="bg-primary text-white">
<body class="cl-site-shell @pageTone bg-primary text-white">
@if (IsSectionDefined("BackgroundVideo"))
{
@RenderSection("BackgroundVideo", required: false)
@ -76,7 +90,7 @@
<div class="content">
<!-- Content wrapper to keep everything on top of the background -->
<header>
<nav class="navbar fixed-top navbar-expand-sm navbar-toggleable-sm navbar-dark border-bottom border-2 border-primary box-shadow mb-3 bg-dark">
<nav class="navbar fixed-top navbar-expand-sm navbar-toggleable-sm navbar-dark border-bottom border-2 border-primary box-shadow mb-3 bg-dark cl-navbar">
<div class="container-fluid">
<a class="navbar-brand pe-0 me-0" asp-area="" asp-controller="Home" asp-action="Index">
<img src="~/images/catherine-lynwood-banner-logo-small.png" alt="Catherine Lynwood Logo Banner" class="img-fluid" style="height: 45px; width: 265px;" />
@ -145,7 +159,7 @@
</div>
</nav>
</header>
<div class="container-lg" style="margin-top: 70px;">
<div class="container-lg cl-main-container" style="margin-top: 70px;">
<main role="main" class="p-0">
@RenderBody()
</main>
@ -158,7 +172,7 @@
</svg>
</div>
</div> <!-- End of content wrapper -->
<footer class="border-top border-2 border-primary footer bg-dark py-3" id="site-footer">
<footer class="border-top border-2 border-primary footer bg-dark py-3 cl-footer" id="site-footer">
<div class="container">
<div class="row justify-content-center align-items-center" >
<div class="col-md-6 text-center order-md-2">
@ -227,74 +241,6 @@
@RenderSection("Scripts", required: false)
<script>
(function () {
const mediaMap = {
discovery: {
video: "/videos/background-discovery.mp4",
poster: "/images/webp/the-alpha-flame-discovery-blank-400.webp"
},
reckoning: {
video: "/videos/background-reckoning.mp4",
poster: "/images/webp/the-alpha-flame-reckoning-blank-400.webp"
},
redemption: {
video: "/videos/background-redemption.mp4",
poster: "/images/webp/the-alpha-flame-redemption-blank-400.webp"
},
default: {
video: "/videos/background-reckoning.mp4",
poster: "/images/webp/the-alpha-flame-reckoning-blank-400.webp"
}
};
function pickMedia(pathname) {
const path = (pathname || "/").toLowerCase();
if (path.includes("/discovery")) return mediaMap.discovery;
if (path.includes("/reckoning")) return mediaMap.reckoning;
if (path.includes("/redemption")) return mediaMap.redemption;
return mediaMap.default;
}
function initBackgroundVideo() {
const video = document.getElementById("siteBackgroundVideo");
if (!video) return;
const chosen = pickMedia(window.location.pathname);
// Stop any eager autoplay behaviour while we swap assets
try { video.pause(); } catch {}
// Ensure poster matches route BEFORE loading anything
video.poster = chosen.poster;
// Clear any existing sources to avoid weird caching/duplication issues
video.querySelectorAll("source").forEach(s => s.remove());
const source = document.createElement("source");
source.src = chosen.video;
source.type = "video/mp4";
video.appendChild(source);
// Now load and play
video.load();
video.play().catch(err => {
console.warn("Background video autoplay failed:", err);
});
}
// Run ASAP once the DOM exists
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initBackgroundVideo);
} else {
initBackgroundVideo();
}
})();
</script>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {

View File

@ -2,36 +2,10 @@
Layout = "/Views/Shared/_Layout.cshtml";
}
@section CSS{
<style>
.video-overlay {
background-color: rgba(13, 202, 240, 0.2);
}
</style>
}
@section Meta {
@RenderSection("Meta", required: false)
}
@section BackgroundVideo {
<div id="background-wrapper">
<div class="video-background">
<video id="siteBackgroundVideo"
autoplay
muted
loop
playsinline
preload="none">
<!-- Source will be injected by JS -->
</video>
<div class="video-overlay"></div>
</div>
</div>
}
@RenderBody()
@section Scripts {

View File

@ -6,22 +6,6 @@
@RenderSection("Meta", required: false)
}
@section BackgroundVideo {
<div id="background-wrapper">
<div class="video-background">
<video id="siteBackgroundVideo"
autoplay
muted
loop
playsinline
preload="none">
<!-- Source will be injected by JS -->
</video>
<div class="video-overlay"></div>
</div>
</div>
}
@RenderBody()
@section Scripts {

View File

@ -33,18 +33,19 @@
</div>
<div class="row my-4">
<div class="col-12 text-center">
<div class="col-12 text-center cl-editorial-hero">
<p class="cl-kicker mb-2">Author journal</p>
<h1 class="display-4">
<i class="fad fa-coffee" style="--fa-primary-color: #ffffff; --fa-secondary-color: #042830;"></i>
A Cuppa With Catherine
</h1>
<p class="lead mt-3 px-3">
Pop the kettle on and settle in for a cuppa. Catherine Lynwood invites you to share in her updates, reflections, and the worlds and characters she brings to life—like old friends having a natter over tea.
Pop the kettle on and settle in for truthful notes from the writing desk: book news, behind-the-scenes reflections, and the lived-in worlds Catherine brings to life.
</p>
</div>
</div>
<form method="get" class="row border border-1 rounded-3 bg-white mx-0 mb-3">
<form method="get" class="row border border-1 rounded-3 bg-white mx-0 mb-3 cl-journal-filter">
<div class="col-12 pt-3">
<div class="row justify-content-center">
<div class="col-md-2 col-md-10 col-lg-9 col-xl-8 col-xxl-7">
@ -149,7 +150,7 @@ else
@if (!string.IsNullOrEmpty(Model.NextBlog.Title))
{
<div class="col-12 mb-3">
<div class="card h-100 shadow-lg border-3 border-dark">
<div class="card h-100 shadow-lg border-3 border-dark cl-feature-card">
<div class="row g-0">
<div class="col-md-1">
<responsive-image src="@Model.NextBlog.ImageUrl" class="img-fluid rounded-start-3" alt="@Model.NextBlog.ImageAlt" display-width-percentage="30"></responsive-image>
@ -169,7 +170,7 @@ else
{
<div class="col-sm-6 col-md-4 mb-4 d-flex">
<div class="card shadow-sm">
<div class="card shadow-sm cl-feature-card">
<div class="card-header text-center">
<h2 class="h5 card-title">@item.Title</h2>
<small class="text-muted">@item.SubTitle</small>
@ -208,7 +209,7 @@ else
}
<div class="col-12 mb-3">
<div class="card shadow-sm">
<div class="card shadow-sm cl-feature-card">
<div class="card-body">
<p class="h5">Got an idea for a future blog post?</p>
<p>If you would like to ask me a question or have a suggestion for a future blog them please don't be shy. <a asp-controller="AskAQuestion" asp-action="Index"> Go to my ask a question form and let me know.</a></p>

View File

@ -54,8 +54,6 @@
<div class="col-12">
@if (!string.IsNullOrWhiteSpace(Model.ImageUrl) && !string.IsNullOrWhiteSpace(Model.ContentTop))
{
var posterImage = $"/images/webp/{Model.DefaultWebpImage}";
<responsive-image src="@Model.ImageUrl"
class="d-none"
alt="The Alpha Flame: Discovery by Catherine Lynwood"
@ -74,12 +72,10 @@
}
else
{
<div class="hero-video-container">
<video id="heroVideo" autoplay muted loop playsinline preload="none" poster="@posterImage">
<!-- Source will be injected later -->
</video>
</div>
@Html.Raw(Model.ImageDescription)
<figure>
<responsive-image src="@Model.ImageUrl" alt="@Model.ImageAlt" class="img-fluid rounded-5 border border-3 border-dark shadow-lg" display-width-percentage="50"></responsive-image>
<figcaption>@Html.Raw(Model.ImageDescription)</figcaption>
</figure>
}
</div>
@ -96,12 +92,10 @@
}
else
{
<div class="hero-video-container">
<video id="heroVideo" autoplay muted loop playsinline preload="none" poster="@posterImage">
<!-- Source will be injected later -->
</video>
</div>
@Html.Raw(Model.ImageDescription)
<figure>
<responsive-image src="@Model.ImageUrl" alt="@Model.ImageAlt" class="img-fluid rounded-5 border border-3 border-dark shadow-lg" display-width-percentage="50"></responsive-image>
<figcaption>@Html.Raw(Model.ImageDescription)</figcaption>
</figure>
}
</div>
@ -166,25 +160,6 @@
const player = new Plyr('audio');
</script>
@if (!string.IsNullOrEmpty(Model.VideoUrl))
{
<script>
window.addEventListener("load", () => {
setTimeout(() => {
const video = document.getElementById("heroVideo");
const source = document.createElement("source");
source.src = "/videos/@Model.VideoUrl";
source.type = "video/mp4";
video.appendChild(source);
video.load(); // Triggers actual file load
video.play().catch(err => {
console.warn("Autoplay failed:", err);
});
}, 2000); // Adjust delay (e.g., 1000–3000ms) based on your needs
});
</script>
}
<script>
function disableSubmit(form) {
const button = form.querySelector('button[type="submit"]');
@ -209,12 +184,9 @@
og-site-name="Catherine Lynwood - The Alpha Flame"
article-published-time="@Model.PublishDate"
article-modified-time="@DateTime.UtcNow"
twitter-card-type="@(string.IsNullOrWhiteSpace(Model.VideoUrl) ? "summary_large_image" : "player")"
twitter-card-type="summary_large_image"
twitter-site-handle="@@CathLynwood"
twitter-creator-handle="@@CathLynwood"
twitter-video-url="@(string.IsNullOrWhiteSpace(Model.VideoUrl) ? null : $"https://www.catherinelynwood.com/videos/{Model.VideoUrl}")"
twitter-player-width="@(string.IsNullOrWhiteSpace(Model.VideoUrl) ? null : 480)"
twitter-player-height="@(string.IsNullOrWhiteSpace(Model.VideoUrl) ? null : 80)" />
twitter-creator-handle="@@CathLynwood" />
<script type="application/ld+json">

View File

@ -14,7 +14,8 @@
</div>
<div class="container py-2">
<div class="text-center mb-5">
<div class="text-center mb-5 cl-editorial-hero">
<p class="cl-kicker mb-2">A Verostic trilogy</p>
<h1 class="display-5 fw-bold">The Alpha Flame Trilogy</h1>
<p class="lead">
A powerful series of love, trauma, discovery and transformation.
@ -26,7 +27,7 @@
<!-- Book 1: Full-width Featured -->
<div class="row mb-5">
<div class="col-12">
<div class="card h-100 shadow-lg border-3 border-dark">
<div class="card h-100 shadow-lg border-3 border-dark cl-feature-card">
<div class="row g-0">
<div class="col-md-3 d-none d-md-block border-end border-dark border-3">
<a asp-controller="Discovery" asp-action="Index">
@ -69,7 +70,7 @@
<div class="row mb-4">
<div class="col-12">
<div class="card h-100 shadow-sm border-start border-3 border-dark position-relative">
<div class="card h-100 shadow-sm border-start border-3 border-dark position-relative cl-feature-card">
<span class="badge bg-warning text-dark position-absolute top-0 start-0 m-2">Coming 1st April 2026</span>
<div class="row g-0">
<div class="col-md-3 d-none d-md-block border-end border-dark border-3">
@ -116,7 +117,7 @@
@*
<div class="row mb-4">
<div class="col-12">
<div class="card h-100 shadow-sm border-start border-3 border-dark position-relative">
<div class="card h-100 shadow-sm border-start border-3 border-dark position-relative cl-feature-card">
<div class="row g-0">
<div class="col-md-8 d-none d-md-block">
<a asp-action="Characters">

View File

@ -147,24 +147,6 @@
const player = new Plyr('audio');
</script>
@if (!string.IsNullOrEmpty(Model.VideoUrl))
{
<script>
window.addEventListener("load", () => {
setTimeout(() => {
const video = document.getElementById("heroVideo");
const source = document.createElement("source");
source.src = "/videos/@Model.VideoUrl";
source.type = "video/mp4";
video.appendChild(source);
video.load(); // Triggers actual file load
video.play().catch(err => {
console.warn("Autoplay failed:", err);
});
}, 2000); // Adjust delay (e.g., 1000–3000ms) based on your needs
});
</script>
}
}
@section Meta {
@ -178,12 +160,9 @@
og-site-name="Catherine Lynwood - The Alpha Flame"
article-published-time="@Model.PublishDate"
article-modified-time="@DateTime.UtcNow"
twitter-card-type="@(string.IsNullOrWhiteSpace(Model.VideoUrl) ? "summary_large_image" : "player")"
twitter-card-type="summary_large_image"
twitter-site-handle="@@CathLynwood"
twitter-creator-handle="@@CathLynwood"
twitter-video-url="@(string.IsNullOrWhiteSpace(Model.VideoUrl) ? null : $"https://www.catherinelynwood.com/videos/{Model.VideoUrl}")"
twitter-player-width="@(string.IsNullOrWhiteSpace(Model.VideoUrl) ? null : 480)"
twitter-player-height="@(string.IsNullOrWhiteSpace(Model.VideoUrl) ? null : 80)" />
twitter-creator-handle="@@CathLynwood" />
<script type="application/ld+json">

View File

@ -154,3 +154,702 @@ section {
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
}
/* Catherine Lynwood brand facelift */
:root {
--cl-ink: #181514;
--cl-ink-soft: #26211f;
--cl-paper: #f3ebdd;
--cl-paper-deep: #e5d5bd;
--cl-rose: #8e3a4a;
--cl-mulberry: #4b243a;
--cl-tea: #c8a982;
--cl-rain: #73706d;
--cl-copper: #b56945;
--cl-line: rgba(200, 169, 130, 0.36);
--cl-shadow: 0 1.1rem 2.8rem rgba(16, 12, 10, 0.28);
--cl-heading-font: Georgia, "Times New Roman", serif;
--cl-body-font: "Segoe UI", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
}
body.cl-site-shell {
color: var(--cl-paper);
background:
radial-gradient(circle at 18% 8%, rgba(142, 58, 74, 0.24), transparent 26rem),
linear-gradient(135deg, #211b19 0%, #181514 48%, #090807 100%) !important;
font-family: var(--cl-body-font);
letter-spacing: 0;
}
.cl-site-shell .static-background {
background-image:
linear-gradient(rgba(24, 21, 20, 0.78), rgba(24, 21, 20, 0.9)),
url('/images/webp/the-alpha-flame-reckoning-blank-960.webp');
filter: saturate(0.74) contrast(1.06);
}
.cl-site-shell .video-overlay {
background:
linear-gradient(90deg, rgba(24, 21, 20, 0.88), rgba(24, 21, 20, 0.42) 48%, rgba(24, 21, 20, 0.82)),
linear-gradient(0deg, rgba(24, 21, 20, 0.92), transparent 58%) !important;
}
.cl-site-shell h1,
.cl-site-shell h2,
.cl-site-shell h3,
.cl-site-shell h4,
.cl-site-shell .display-1,
.cl-site-shell .display-2,
.cl-site-shell .display-3,
.cl-site-shell .display-4,
.cl-site-shell .display-5,
.cl-site-shell .display-6 {
color: var(--cl-paper);
font-family: var(--cl-heading-font);
font-weight: 500;
letter-spacing: 0;
}
.cl-site-shell p,
.cl-site-shell li {
line-height: 1.72;
}
.cl-site-shell a {
color: var(--cl-tea);
text-underline-offset: 0.18em;
}
.cl-site-shell a:hover,
.cl-site-shell a:focus {
color: var(--cl-paper);
}
.cl-site-shell .lead {
color: rgba(243, 235, 221, 0.86);
font-family: var(--cl-heading-font);
}
.bg-primary {
background-color: var(--cl-ink) !important;
}
.bg-dark {
background-color: rgba(17, 14, 13, 0.94) !important;
}
.text-primary,
.text-primary-emphasis {
color: var(--cl-tea) !important;
}
.text-muted {
color: rgba(38, 33, 31, 0.62) !important;
}
.cl-site-shell .text-white .text-muted,
.cl-site-shell .bg-dark .text-muted,
.cl-site-shell > .content .text-muted {
color: rgba(243, 235, 221, 0.68) !important;
}
.border-primary,
.border-dark {
border-color: var(--cl-line) !important;
}
.cl-navbar {
border-bottom-color: rgba(200, 169, 130, 0.34) !important;
box-shadow: 0 0.75rem 2.5rem rgba(0, 0, 0, 0.25);
backdrop-filter: blur(14px);
}
.cl-navbar .navbar-brand img {
filter: sepia(0.16) saturate(0.78) brightness(1.05);
}
.cl-navbar .nav-link {
color: rgba(243, 235, 221, 0.76) !important;
font-size: 0.88rem;
font-weight: 650;
letter-spacing: 0.02em;
}
.cl-navbar .nav-link:hover,
.cl-navbar .nav-link:focus,
.cl-navbar .nav-link.show {
color: var(--cl-paper) !important;
}
.cl-navbar .dropdown-menu {
background: var(--cl-paper);
border: 1px solid var(--cl-line);
border-radius: 4px;
box-shadow: var(--cl-shadow);
}
.cl-navbar .dropdown-item {
color: var(--cl-ink);
}
.cl-navbar .dropdown-item:hover,
.cl-navbar .dropdown-item:focus {
color: var(--cl-paper);
background: var(--cl-mulberry);
}
.cl-main-container {
padding-top: 1rem;
padding-bottom: 3rem;
}
.breadcrumb {
--bs-breadcrumb-divider-color: rgba(243, 235, 221, 0.48);
margin-bottom: 1.35rem;
font-size: 0.82rem;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.breadcrumb-item,
.breadcrumb-item a,
.breadcrumb-item a:visited {
color: rgba(243, 235, 221, 0.72) !important;
}
.breadcrumb-item.active {
color: var(--cl-paper) !important;
}
.cl-site-shell .card,
.cl-site-shell .character-card,
.cl-site-shell .accordion-item,
.cl-site-shell .modal-content,
.cl-site-shell form.bg-white,
.cl-panel {
color: var(--cl-ink);
background:
linear-gradient(135deg, rgba(255, 255, 255, 0.34), rgba(255, 255, 255, 0)),
var(--cl-paper);
border: 1px solid rgba(75, 36, 58, 0.22) !important;
border-radius: 6px !important;
box-shadow: var(--cl-shadow);
}
.cl-site-shell .card-header {
color: var(--cl-ink);
background: rgba(229, 213, 189, 0.78);
border-bottom: 1px solid rgba(75, 36, 58, 0.18);
}
.cl-site-shell .card h1,
.cl-site-shell .card h2,
.cl-site-shell .card h3,
.cl-site-shell .card h4,
.cl-site-shell .card h5,
.cl-site-shell .card h6,
.cl-site-shell .accordion-item h2,
.cl-site-shell .modal-content h5 {
color: var(--cl-ink);
}
.cl-site-shell .card .text-muted,
.cl-site-shell .accordion-item .text-muted,
.cl-site-shell .modal-content .text-muted {
color: rgba(38, 33, 31, 0.62) !important;
}
.cl-site-shell .card a:not(.btn),
.cl-site-shell .accordion-item a:not(.btn),
.cl-site-shell .modal-content a:not(.btn) {
color: var(--cl-mulberry);
font-weight: 650;
}
.cl-site-shell .card-img,
.cl-site-shell .card-img-top,
.cl-site-shell .img-fluid,
.cl-site-shell .fit-image {
filter: saturate(0.88) contrast(1.03);
}
.cl-site-shell .rounded-4,
.cl-site-shell .rounded-5 {
border-radius: 6px !important;
}
.cl-site-shell .btn {
border-radius: 2px;
font-weight: 750;
letter-spacing: 0.015em;
box-shadow: none;
}
.cl-site-shell .btn-dark {
color: var(--cl-paper);
background: var(--cl-mulberry);
border-color: var(--cl-mulberry);
}
.cl-site-shell .btn-dark:hover,
.cl-site-shell .btn-dark:focus {
color: var(--cl-paper);
background: var(--cl-rose);
border-color: var(--cl-rose);
}
.cl-site-shell .btn-outline-dark,
.cl-site-shell .btn-outline-secondary,
.cl-site-shell .btn-outline-light {
color: var(--cl-paper);
background: transparent;
border-color: rgba(200, 169, 130, 0.56);
}
.cl-site-shell .btn-outline-dark:hover,
.cl-site-shell .btn-outline-dark:focus,
.cl-site-shell .btn-outline-secondary:hover,
.cl-site-shell .btn-outline-secondary:focus,
.cl-site-shell .btn-outline-light:hover,
.cl-site-shell .btn-outline-light:focus {
color: var(--cl-paper);
background: var(--cl-mulberry);
border-color: var(--cl-mulberry);
}
.cl-site-shell .card .btn-outline-dark,
.cl-site-shell .card .btn-outline-secondary,
.cl-site-shell form.bg-white .btn-outline-dark,
.cl-site-shell form.bg-white .btn-outline-secondary,
.cl-site-shell .modal-content .btn-outline-dark {
color: var(--cl-mulberry);
border-color: rgba(75, 36, 58, 0.56);
}
.cl-site-shell .badge.bg-dark {
color: var(--cl-paper);
background: var(--cl-mulberry) !important;
border-radius: 2px;
}
.cl-site-shell .badge.bg-warning {
color: var(--cl-ink) !important;
background: var(--cl-tea) !important;
border-radius: 2px;
}
.cl-site-shell .form-control,
.cl-site-shell .form-select,
.cl-site-shell .input-group-text {
color: var(--cl-ink);
background-color: #fffaf2;
border-color: rgba(75, 36, 58, 0.26);
border-radius: 2px;
}
.cl-site-shell .form-control:focus,
.cl-site-shell .form-select:focus {
border-color: var(--cl-rose);
box-shadow: 0 0 0 0.18rem rgba(142, 58, 74, 0.18);
}
.cl-site-shell .pagination {
--bs-pagination-color: var(--cl-mulberry);
--bs-pagination-hover-color: var(--cl-rose);
--bs-pagination-active-color: var(--cl-paper);
--bs-pagination-active-bg: var(--cl-mulberry);
--bs-pagination-active-border-color: var(--cl-mulberry);
--bs-pagination-focus-box-shadow: 0 0 0 0.18rem rgba(142, 58, 74, 0.18);
}
.cl-editorial-hero .fa-coffee {
--fa-primary-color: var(--cl-paper) !important;
--fa-secondary-color: var(--cl-tea) !important;
}
.cl-site-shell blockquote {
border-left-color: var(--cl-rose);
color: var(--cl-ink);
}
.cl-site-shell hr {
border-color: rgba(200, 169, 130, 0.38);
opacity: 1;
}
.hero-video-container,
.trailer-wrapper {
border-color: rgba(200, 169, 130, 0.55);
border-radius: 6px;
box-shadow: 0 1.2rem 3rem rgba(0, 0, 0, 0.46);
}
.trailer-play-btn {
background: rgba(75, 36, 58, 0.82);
}
.trailer-play-btn:hover {
background: rgba(142, 58, 74, 0.9);
}
#buyBox {
background:
linear-gradient(135deg, rgba(255, 255, 255, 0.32), rgba(255, 255, 255, 0)),
var(--cl-paper) !important;
border-color: rgba(75, 36, 58, 0.28) !important;
border-radius: 6px !important;
color: var(--cl-ink);
}
.price-chip {
color: var(--cl-ink);
background: var(--cl-tea);
border-color: rgba(75, 36, 58, 0.28);
}
.chapter-text-scroll {
background-color: var(--cl-paper);
border-color: rgba(75, 36, 58, 0.28);
color: var(--cl-ink);
}
.chapter-text-scroll p.active {
background-color: rgba(142, 58, 74, 0.12);
border-left-color: var(--cl-rose);
}
.progress-container,
.progress-bar {
background-color: var(--cl-mulberry);
}
.chapter-tick {
background: var(--cl-tea);
}
.chapter-tick-label {
color: var(--cl-paper);
}
.share-button {
border-radius: 2px;
background-color: var(--cl-mulberry) !important;
}
.share-button:hover,
.follow-icon:hover {
color: var(--cl-paper);
background-color: var(--cl-rose) !important;
}
.cl-footer {
border-top-color: rgba(200, 169, 130, 0.34) !important;
color: rgba(243, 235, 221, 0.72);
}
.scroll-hint {
color: var(--cl-paper);
background: rgba(75, 36, 58, 0.82);
box-shadow: 0 0.7rem 1.8rem rgba(0, 0, 0, 0.36);
}
.cl-editorial-hero {
position: relative;
padding: clamp(2.25rem, 6vw, 5.5rem);
margin-bottom: clamp(1.5rem, 4vw, 3rem);
background:
linear-gradient(135deg, rgba(75, 36, 58, 0.9), rgba(24, 21, 20, 0.86)),
url('/images/webp/the-alpha-flame-reckoning-blank-960.webp') center / cover;
border: 1px solid rgba(200, 169, 130, 0.34);
box-shadow: var(--cl-shadow);
}
.cl-editorial-hero::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(90deg, rgba(24, 21, 20, 0.08), rgba(24, 21, 20, 0.54));
pointer-events: none;
}
.cl-editorial-hero > * {
position: relative;
z-index: 1;
}
.cl-kicker {
color: var(--cl-tea);
font-size: 0.78rem;
font-weight: 750;
letter-spacing: 0.16em;
text-transform: uppercase;
}
.cl-feature-card {
overflow: hidden;
}
.cl-feature-card .card-body {
padding: clamp(1.25rem, 3vw, 2.5rem);
}
.cl-journal-filter {
background:
linear-gradient(135deg, rgba(255, 255, 255, 0.26), rgba(255, 255, 255, 0)),
rgba(243, 235, 221, 0.94) !important;
}
.cl-site-shell .accordion-button {
color: var(--cl-ink);
background: var(--cl-paper);
box-shadow: none;
}
.cl-site-shell .accordion-button:not(.collapsed) {
color: var(--cl-paper);
background: var(--cl-mulberry);
}
@media (max-width: 575.98px) {
.cl-main-container {
padding-left: 1rem;
padding-right: 1rem;
}
.cl-navbar .navbar-brand img {
width: 220px !important;
height: auto !important;
}
}
/* Static author-world visual pass */
#background-wrapper,
.cl-site-shell .video-background,
.cl-site-shell .static-background {
position: fixed;
inset: 0;
width: 100%;
height: 100%;
}
#background-wrapper {
z-index: 0;
overflow: hidden;
}
.cl-site-shell .video-background,
.cl-site-shell .static-background {
z-index: 0;
}
.cl-site-shell .video-background video {
display: none !important;
}
.cl-site-shell .static-background {
background-image:
linear-gradient(90deg, rgba(14, 12, 11, 0.92), rgba(30, 22, 22, 0.74) 52%, rgba(14, 12, 11, 0.94)),
linear-gradient(0deg, rgba(14, 12, 11, 0.96), rgba(14, 12, 11, 0.42) 45%, rgba(14, 12, 11, 0.78)),
url('/images/webp/1983-birmingham-1920.webp');
background-position: center;
background-size: cover;
filter: saturate(0.62) contrast(1.08) brightness(0.82);
}
.cl-site-shell .static-background::before,
.cl-site-shell .static-background::after {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
}
.cl-site-shell .static-background::before {
background:
radial-gradient(circle at 24% 18%, rgba(142, 58, 74, 0.32), transparent 24rem),
radial-gradient(circle at 82% 30%, rgba(181, 105, 69, 0.18), transparent 26rem);
}
.cl-site-shell .static-background::after {
opacity: 0.16;
mix-blend-mode: soft-light;
background-image:
repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.18) 0 1px, transparent 1px 3px),
linear-gradient(rgba(255, 255, 255, 0.08), transparent);
}
.cl-page-home .static-background,
.cl-page-guide .static-background {
background-image:
linear-gradient(90deg, rgba(14, 12, 11, 0.92), rgba(32, 24, 23, 0.68) 52%, rgba(14, 12, 11, 0.94)),
linear-gradient(0deg, rgba(14, 12, 11, 0.98), rgba(14, 12, 11, 0.42) 48%, rgba(14, 12, 11, 0.78)),
url('/images/webp/1983-birmingham-1920.webp');
}
.cl-page-discovery .static-background {
background-image:
linear-gradient(90deg, rgba(12, 12, 12, 0.96), rgba(30, 29, 26, 0.68) 48%, rgba(12, 12, 12, 0.94)),
linear-gradient(0deg, rgba(12, 12, 12, 0.98), rgba(12, 12, 12, 0.44) 52%, rgba(12, 12, 12, 0.76)),
url('/images/webp/rubery-hill-hospital-1920.webp');
background-position: center top;
filter: saturate(0.42) contrast(1.16) brightness(0.74);
}
.cl-page-journal .static-background {
background-image:
linear-gradient(90deg, rgba(17, 13, 12, 0.94), rgba(44, 28, 29, 0.7) 52%, rgba(17, 13, 12, 0.96)),
linear-gradient(0deg, rgba(17, 13, 12, 0.98), rgba(17, 13, 12, 0.42) 48%, rgba(17, 13, 12, 0.76)),
url('/images/webp/the-alpha-flame-discovery-open-on-the-table-maggie-1920.webp');
}
.cl-page-reckoning .static-background {
background-image:
linear-gradient(90deg, rgba(12, 10, 9, 0.92), rgba(35, 22, 21, 0.68) 52%, rgba(12, 10, 9, 0.94)),
linear-gradient(0deg, rgba(12, 10, 9, 0.98), rgba(12, 10, 9, 0.38) 48%, rgba(12, 10, 9, 0.78)),
url('/images/webp/walnut-desktop.webp');
}
.cl-editorial-hero {
overflow: hidden;
background:
linear-gradient(135deg, rgba(75, 36, 58, 0.88), rgba(24, 21, 20, 0.76) 58%, rgba(24, 21, 20, 0.92)),
url('/images/webp/1983-birmingham-1400.webp') center / cover;
backdrop-filter: blur(1px);
}
.cl-page-discovery .cl-editorial-hero {
background:
linear-gradient(135deg, rgba(75, 36, 58, 0.88), rgba(24, 21, 20, 0.78) 58%, rgba(24, 21, 20, 0.94)),
url('/images/webp/rubery-hill-hospital-1400.webp') center top / cover;
}
.cl-cover-feature {
position: relative;
isolation: isolate;
display: inline-block;
width: min(100%, 31rem);
padding: clamp(0.55rem, 1.6vw, 0.95rem);
background:
linear-gradient(145deg, rgba(243, 235, 221, 0.14), rgba(75, 36, 58, 0.26)),
rgba(16, 12, 10, 0.7);
border: 1px solid rgba(200, 169, 130, 0.44);
border-radius: 6px;
box-shadow: 0 2rem 4.6rem rgba(0, 0, 0, 0.52);
}
.cl-cover-feature::before {
content: "";
position: absolute;
inset: 0.55rem;
z-index: -1;
border: 1px solid rgba(243, 235, 221, 0.14);
}
.cl-cover-feature__image {
display: block;
width: 100%;
border-radius: 4px;
filter: saturate(0.82) contrast(1.04) brightness(0.92);
}
.cl-cover-feature__label {
position: absolute;
right: clamp(1rem, 3vw, 1.75rem);
bottom: clamp(1rem, 3vw, 1.75rem);
max-width: calc(100% - 2rem);
padding: 0.55rem 0.75rem;
color: var(--cl-paper);
text-align: right;
background: rgba(24, 21, 20, 0.72);
border-left: 3px solid var(--cl-tea);
backdrop-filter: blur(3px);
}
.cl-cover-feature__label span,
.cl-cover-feature__label strong {
display: block;
line-height: 1.05;
}
.cl-cover-feature__label span {
color: var(--cl-tea);
font-size: 0.72rem;
font-weight: 750;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.cl-cover-feature__label strong {
font-family: var(--cl-heading-font);
font-size: clamp(1.45rem, 4vw, 2.55rem);
font-weight: 500;
}
.cl-trailer-still {
position: relative;
display: block;
overflow: hidden;
color: var(--cl-paper);
text-decoration: none;
border: 1px solid rgba(75, 36, 58, 0.28);
border-radius: 6px;
box-shadow: 0 1.1rem 2.6rem rgba(24, 21, 20, 0.24);
}
.cl-trailer-still__image {
display: block;
width: 100%;
filter: saturate(0.74) contrast(1.07) brightness(0.9);
transition: transform 220ms ease, filter 220ms ease;
}
.cl-trailer-still__veil {
position: absolute;
inset: 0;
background:
linear-gradient(90deg, rgba(24, 21, 20, 0.52), transparent 46%, rgba(75, 36, 58, 0.34)),
linear-gradient(0deg, rgba(24, 21, 20, 0.54), transparent 46%);
}
.cl-trailer-still__button {
position: absolute;
left: 50%;
top: 50%;
display: inline-flex;
align-items: center;
gap: 0.6rem;
padding: 0.72rem 0.95rem;
color: var(--cl-paper);
background: rgba(75, 36, 58, 0.88);
border: 1px solid rgba(243, 235, 221, 0.28);
border-radius: 999px;
font-weight: 750;
transform: translate(-50%, -50%);
box-shadow: 0 0.8rem 2rem rgba(0, 0, 0, 0.32);
}
.cl-trailer-still:hover,
.cl-trailer-still:focus {
color: var(--cl-paper);
}
.cl-trailer-still:hover .cl-trailer-still__image,
.cl-trailer-still:focus .cl-trailer-still__image {
filter: saturate(0.86) contrast(1.1) brightness(0.98);
transform: scale(1.025);
}
.cl-trailer-still--portrait {
max-width: 28rem;
margin-inline: auto;
}
.cl-site-shell .character-card {
backdrop-filter: blur(4px);
}
.cl-site-shell .carousel-caption {
color: var(--cl-paper);
background: rgba(24, 21, 20, 0.72);
border-left: 3px solid var(--cl-tea);
}

File diff suppressed because one or more lines are too long