Files
xtremflow/web/xf-player.css
T
MichaelandClaude Opus 5 1feeaae78a feat(design): Warm Cinema theme + event-driven adaptive players
Replaces the Projector Noir palette with "Warm Cinema" and rebuilds the
web players around a shared, event-driven engine.

Design
- app_colors: warm charcoal (#0B0908), cream (#F3E9DF), ember (#D9541F);
  adds posterScrim/heroScrim gradients, lift()/emberFocus() shadows,
  const cream-alpha tokens replacing Colors.whiteNN, and primaryFill,
  a deeper ember reserved for text-bearing fills so white labels clear
  the 4.5:1 AA threshold that #D9541F alone does not
- app_theme / mobile_theme: Fraunces (display serif) + Karla (body),
  tighter radii, 20+ component themes
- glass_container: opaque layered surfaces replace the blurred glass
- themed_loading_screen restyled; players and boot splash follow

Performance
- drop every BackdropFilter: backdrop blur forced a full framebuffer
  read per frame per card, the main source of scroll jank
- bundle Fraunces/Karla as assets so google_fonts stops fetching from
  fonts.gstatic.com at startup
- bound image decode size on 12 sites: a 40-poster grid drops from
  ~240 MB to a few tens of MB of GPU memory

Players (new shared engine: web/xf-player-core.js)
- start on media events instead of polling the buffer every 100-200 ms
- hls.js/mpegts.js loaded on demand, so ~213 KB of mpegts is never
  fetched for HLS streams
- liveSyncDurationCount 10 -> 2, startFragPrefetch on, testBandwidth
  off, MPEG-TS initial stash 512 KB -> 64 KB
- adaptive escalation fast -> balanced -> safe after repeated stalls in
  a 60 s window, applied live for HLS so there is no visible cut

Preserved from the recent streaming work on main: server-side quality
selection, stable player viewId, the turbo direct MPEG-TS path, vendored
library cache headers and the CI/Docker changes. Only the theme layer and
the player front-end were replaced; GlassCard stays in ui_components.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 21:42:56 +02:00

256 lines
5.2 KiB
CSS

/* =====================================================================
* XtremFlow — Habillage des lecteurs, thème « Warm Cinema »
* Charbon chaud (#0B0908), crème (#F3E9DF), braise (#D9541F).
*
* PERF : aucun backdrop-filter. Le flou de fond force le compositeur à
* relire le framebuffer à chaque frame — inacceptable par-dessus une vidéo.
* ===================================================================== */
:root {
--xf-ink: #0B0908;
--xf-cream: #F3E9DF;
--xf-cream-dim: #C5B3A5;
--xf-ember: #D9541F;
--xf-ember-light: #FFB68C;
--xf-danger: #E5484D;
--xf-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
html,
body {
background: var(--xf-ink);
width: 100%;
height: 100%;
overflow: hidden;
font-family: var(--xf-ui);
color: var(--xf-cream);
}
#player-container {
width: 100%;
height: 100%;
position: relative;
background: var(--xf-ink);
}
#video {
width: 100%;
height: 100%;
background: var(--xf-ink);
display: block;
}
/* ---------------------------------------------------------------
* Amorce de projection — l'anneau de compte à rebours d'une bobine
* --------------------------------------------------------------- */
.xf-center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
z-index: 20;
}
#loading {
display: none;
}
.xf-leader {
width: 64px;
height: 64px;
margin: 0 auto 20px;
position: relative;
}
/* Anneau fixe, très discret */
.xf-leader::before {
content: "";
position: absolute;
inset: 0;
border-radius: 50%;
border: 2px solid rgba(243, 233, 223, 0.14);
}
/* Balayage braise */
.xf-leader::after {
content: "";
position: absolute;
inset: 0;
border-radius: 50%;
border: 2px solid transparent;
border-top-color: var(--xf-ember);
border-right-color: var(--xf-ember);
animation: xf-sweep 900ms cubic-bezier(0.5, 0, 0.5, 1) infinite;
}
/* Réticule central : croix d'amorce de pellicule */
.xf-leader-cross,
.xf-leader-cross::before {
position: absolute;
background: rgba(243, 233, 223, 0.22);
}
.xf-leader-cross {
top: 50%;
left: 12px;
right: 12px;
height: 1px;
transform: translateY(-0.5px);
}
.xf-leader-cross::before {
content: "";
top: -14px;
bottom: -14px;
left: 50%;
width: 1px;
height: 28px;
transform: translateX(-0.5px);
}
@keyframes xf-sweep {
to {
transform: rotate(360deg);
}
}
.xf-label {
font-size: 12px;
font-weight: 600;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--xf-cream-dim);
}
/* Mention discrète quand le buffer s'élargit tout seul */
.xf-hint {
margin-top: 10px;
font-size: 11px;
letter-spacing: 0.08em;
color: rgba(243, 233, 223, 0.42);
min-height: 14px;
}
/* ---------------------------------------------------------------
* Erreur
* --------------------------------------------------------------- */
#error {
display: none;
max-width: 78vw;
}
.xf-error-mark {
width: 52px;
height: 52px;
margin: 0 auto 18px;
border: 2px solid var(--xf-danger);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 26px;
line-height: 1;
color: var(--xf-danger);
}
.xf-error-title {
font-size: 15px;
font-weight: 700;
letter-spacing: 0.02em;
color: var(--xf-cream);
}
.xf-error-sub {
margin-top: 8px;
font-size: 12px;
letter-spacing: 0.04em;
color: rgba(243, 233, 223, 0.5);
}
/* ---------------------------------------------------------------
* Overlay lecture (autoplay bloqué)
* --------------------------------------------------------------- */
#play-overlay {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 92px;
height: 92px;
border-radius: 50%;
background: rgba(11, 9, 8, 0.82);
border: 2px solid var(--xf-ember);
box-shadow: 0 0 40px rgba(217, 84, 31, 0.35);
display: none;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 25;
transition: transform 160ms cubic-bezier(0.16, 1, 0.3, 1);
}
#play-overlay:hover {
transform: translate(-50%, -50%) scale(1.06);
}
#play-overlay:active {
transform: translate(-50%, -50%) scale(0.94);
}
#play-overlay svg {
width: 40px;
height: 40px;
fill: var(--xf-cream);
margin-left: 5px;
}
/* ---------------------------------------------------------------
* Bouton « activer le son » (iOS)
* --------------------------------------------------------------- */
.xf-sound-btn {
position: absolute;
bottom: 26px;
left: 50%;
transform: translateX(-50%);
display: none;
align-items: center;
gap: 9px;
padding: 12px 22px;
border: 1px solid var(--xf-ember);
border-radius: 999px;
background: rgba(11, 9, 8, 0.88);
color: var(--xf-cream);
font-family: var(--xf-ui);
font-size: 12px;
font-weight: 700;
letter-spacing: 0.14em;
text-transform: uppercase;
cursor: pointer;
z-index: 26;
}
.xf-sound-btn svg {
width: 17px;
height: 17px;
fill: var(--xf-ember-light);
}
/* Respect des préférences d'accessibilité */
@media (prefers-reduced-motion: reduce) {
.xf-leader::after {
animation-duration: 2s;
}
#play-overlay {
transition: none;
}
}