Fix contrast (dark text + deep accents), single-line hero title, YouTube above demo, centered intros, robust video autoplay
Browse files- _style.css +56 -18
- app.py +8 -2
_style.css
CHANGED
|
@@ -6,25 +6,60 @@
|
|
| 6 |
============================================================================ */
|
| 7 |
|
| 8 |
:root {
|
| 9 |
-
--ink: #
|
| 10 |
-
--ink-soft: #
|
| 11 |
-
--ink-faint: #
|
| 12 |
-
--
|
| 13 |
-
--
|
| 14 |
-
--
|
|
|
|
|
|
|
| 15 |
--surface: #fbfaf6; /* warm off-white page */
|
| 16 |
--card: #ffffff; /* card surface */
|
| 17 |
-
--card-edge: #
|
| 18 |
-
--shadow: 0 10px 30px rgba(40, 32, 8, 0.
|
| 19 |
-
--shadow-sm: 0 4px 14px rgba(40, 32, 8, 0.
|
| 20 |
--radius: 20px;
|
| 21 |
}
|
| 22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
/* Page surface — soft cream with a faint sunny glow at the top, NOT flat yellow.
|
| 24 |
Transparent sprite + alpha videos read cleanly on this. */
|
|
|
|
| 25 |
.gradio-container,
|
| 26 |
.gradio-container .main,
|
| 27 |
-
|
| 28 |
background:
|
| 29 |
radial-gradient(1100px 520px at 50% -8%, #fff4cf 0%, rgba(255,244,207,0) 60%),
|
| 30 |
radial-gradient(900px 600px at 88% 8%, #eef4ff 0%, rgba(238,244,255,0) 55%),
|
|
@@ -72,14 +107,15 @@ body {
|
|
| 72 |
.hero-center { text-align: center; }
|
| 73 |
.eyebrow {
|
| 74 |
display: inline-flex; align-items: center; gap: 7px;
|
| 75 |
-
background: #
|
| 76 |
-
border: 1.5px solid
|
| 77 |
-
color:
|
| 78 |
-
font-weight:
|
| 79 |
text-transform: uppercase;
|
| 80 |
padding: 6px 14px; border-radius: 999px;
|
| 81 |
box-shadow: var(--shadow-sm);
|
| 82 |
}
|
|
|
|
| 83 |
.eyebrow .dot { width: 7px; height: 7px; border-radius: 50%; background: #2ecc71; box-shadow: 0 0 0 3px rgba(46,204,113,.18); }
|
| 84 |
|
| 85 |
/* Sprite-sheet animation — 12 frames in a 6144x512 strip, ~10 fps.
|
|
@@ -108,9 +144,10 @@ body {
|
|
| 108 |
@keyframes shadow-pulse { 0%,100% { transform: scaleX(1); opacity:.7;} 50%{ transform: scaleX(.82); opacity:.45;} }
|
| 109 |
|
| 110 |
.hero-title {
|
| 111 |
-
font-size: clamp(
|
| 112 |
-
line-height: 1.
|
| 113 |
margin: 6px 0 8px !important;
|
|
|
|
| 114 |
}
|
| 115 |
.hero-title .zap { color: var(--bolt-deep); }
|
| 116 |
.hero-sub {
|
|
@@ -136,9 +173,10 @@ body {
|
|
| 136 |
SECTION SCAFFOLD
|
| 137 |
========================================================================= */
|
| 138 |
.section { margin: 34px 0 0; }
|
| 139 |
-
.section-head { text-align: center; margin-bottom: 18px; }
|
|
|
|
| 140 |
.section-head h2 { font-size: 1.7rem !important; margin: 0 0 6px !important; }
|
| 141 |
-
.section-head p { color:
|
| 142 |
|
| 143 |
.card {
|
| 144 |
background: var(--card); border: 1px solid var(--card-edge);
|
|
|
|
| 6 |
============================================================================ */
|
| 7 |
|
| 8 |
:root {
|
| 9 |
+
--ink: #20242e; /* dark body text (high contrast on cream) */
|
| 10 |
+
--ink-soft: #353a47; /* secondary body — still clearly dark */
|
| 11 |
+
--ink-faint: #4a5160; /* captions — darkened, no longer washed out */
|
| 12 |
+
--accent: #b45309; /* DEEP amber — emphasis, MORE visible than body */
|
| 13 |
+
--accent-2: #3730a3; /* deep indigo — secondary emphasis */
|
| 14 |
+
--bolt: #f6a700; /* electric amber (decorative accents/borders) */
|
| 15 |
+
--bolt-deep: #b45309; /* deep amber for borders/highlights */
|
| 16 |
+
--spark: #3730a3; /* deep indigo link/accent */
|
| 17 |
--surface: #fbfaf6; /* warm off-white page */
|
| 18 |
--card: #ffffff; /* card surface */
|
| 19 |
+
--card-edge: #e2ddd0; /* hairline */
|
| 20 |
+
--shadow: 0 10px 30px rgba(40, 32, 8, 0.12);
|
| 21 |
+
--shadow-sm: 0 4px 14px rgba(40, 32, 8, 0.09);
|
| 22 |
--radius: 20px;
|
| 23 |
}
|
| 24 |
|
| 25 |
+
/* Force a light surface even if the visitor's Gradio theme is dark. */
|
| 26 |
+
:root, .dark, .gradio-container.dark {
|
| 27 |
+
--body-background-fill: var(--surface) !important;
|
| 28 |
+
--background-fill-primary: var(--surface) !important;
|
| 29 |
+
--body-text-color: #20242e !important;
|
| 30 |
+
--body-text-color-subdued: #4a5160 !important;
|
| 31 |
+
color-scheme: light !important;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
/* ============================================================================
|
| 35 |
+
HARD CONTRAST OVERRIDES — Gradio's theme cascade washes text out on the live
|
| 36 |
+
Space (custom-property colors get re-resolved). Pin every text run to a dark
|
| 37 |
+
color with !important so nothing is "only readable when highlighted".
|
| 38 |
+
============================================================================ */
|
| 39 |
+
#pet-app, #pet-app * { color: #20242e; }
|
| 40 |
+
#pet-app p, #pet-app li, #pet-app td, #pet-app .hero-sub,
|
| 41 |
+
#pet-app .section-head p, #pet-app .talk-hint, #pet-app .emotion .desc,
|
| 42 |
+
#pet-app .stack-table td, #pet-app .stack-table th { color: #353a47 !important; }
|
| 43 |
+
#pet-app h1, #pet-app h2, #pet-app h3, #pet-app .name,
|
| 44 |
+
#pet-app .stack-table td:first-child { color: #20242e !important; }
|
| 45 |
+
/* Emphasis must be MORE visible than body, never less */
|
| 46 |
+
#pet-app b, #pet-app strong, #pet-app .prose b, #pet-app .prose li b,
|
| 47 |
+
#pet-app .prose p b, #pet-app .lede b { color: #92400e !important; font-weight: 700; }
|
| 48 |
+
#pet-app .hero-sub b { color: #20242e !important; }
|
| 49 |
+
#pet-app code { color: #92400e !important; background: #f3ede2 !important; }
|
| 50 |
+
#pet-app .chip { color: #20242e !important; }
|
| 51 |
+
#pet-app .eyebrow, #pet-app .eyebrow * { color: #20242e !important; }
|
| 52 |
+
#pet-app .chip.local, #pet-app .chip.local * { color: #ffffff !important; }
|
| 53 |
+
#pet-app .btn-dark, #pet-app .btn-dark * { color: #ffffff !important; }
|
| 54 |
+
#pet-app .foot, #pet-app .foot * { color: #4a5160 !important; }
|
| 55 |
+
#pet-app .foot a { color: #3730a3 !important; }
|
| 56 |
+
|
| 57 |
/* Page surface — soft cream with a faint sunny glow at the top, NOT flat yellow.
|
| 58 |
Transparent sprite + alpha videos read cleanly on this. */
|
| 59 |
+
html, body,
|
| 60 |
.gradio-container,
|
| 61 |
.gradio-container .main,
|
| 62 |
+
.gradio-container.dark {
|
| 63 |
background:
|
| 64 |
radial-gradient(1100px 520px at 50% -8%, #fff4cf 0%, rgba(255,244,207,0) 60%),
|
| 65 |
radial-gradient(900px 600px at 88% 8%, #eef4ff 0%, rgba(238,244,255,0) 55%),
|
|
|
|
| 107 |
.hero-center { text-align: center; }
|
| 108 |
.eyebrow {
|
| 109 |
display: inline-flex; align-items: center; gap: 7px;
|
| 110 |
+
background: #fff4d6; /* warm tinted pill for contrast */
|
| 111 |
+
border: 1.5px solid #f0c64e;
|
| 112 |
+
color: #6b3d06 !important; /* deep amber text — clearly legible */
|
| 113 |
+
font-weight: 700; font-size: 0.78rem; letter-spacing: 0.04em;
|
| 114 |
text-transform: uppercase;
|
| 115 |
padding: 6px 14px; border-radius: 999px;
|
| 116 |
box-shadow: var(--shadow-sm);
|
| 117 |
}
|
| 118 |
+
.eyebrow, .eyebrow * { color: #6b3d06 !important; }
|
| 119 |
.eyebrow .dot { width: 7px; height: 7px; border-radius: 50%; background: #2ecc71; box-shadow: 0 0 0 3px rgba(46,204,113,.18); }
|
| 120 |
|
| 121 |
/* Sprite-sheet animation — 12 frames in a 6144x512 strip, ~10 fps.
|
|
|
|
| 144 |
@keyframes shadow-pulse { 0%,100% { transform: scaleX(1); opacity:.7;} 50%{ transform: scaleX(.82); opacity:.45;} }
|
| 145 |
|
| 146 |
.hero-title {
|
| 147 |
+
font-size: clamp(1.9rem, 4.6vw, 3rem) !important;
|
| 148 |
+
line-height: 1.05;
|
| 149 |
margin: 6px 0 8px !important;
|
| 150 |
+
white-space: nowrap; /* keep "⚡ Pocket Pikachu" on ONE line */
|
| 151 |
}
|
| 152 |
.hero-title .zap { color: var(--bolt-deep); }
|
| 153 |
.hero-sub {
|
|
|
|
| 173 |
SECTION SCAFFOLD
|
| 174 |
========================================================================= */
|
| 175 |
.section { margin: 34px 0 0; }
|
| 176 |
+
.section-head { text-align: center !important; margin-bottom: 18px; }
|
| 177 |
+
.section-head * { text-align: center !important; }
|
| 178 |
.section-head h2 { font-size: 1.7rem !important; margin: 0 0 6px !important; }
|
| 179 |
+
.section-head p { color: #4a5160 !important; font-size: 0.98rem; margin: 0 auto; max-width: 620px; }
|
| 180 |
|
| 181 |
.card {
|
| 182 |
background: var(--card); border: 1px solid var(--card-edge);
|
app.py
CHANGED
|
@@ -376,9 +376,13 @@ def sprite_html(src: str) -> str:
|
|
| 376 |
|
| 377 |
|
| 378 |
def _alpha_video(webm: str, mp4: str, side_class: str, label: str) -> str:
|
|
|
|
|
|
|
| 379 |
return (
|
| 380 |
f"<video class='hero-vid {side_class}' autoplay loop muted playsinline "
|
| 381 |
-
f"aria-label='{label}'
|
|
|
|
|
|
|
| 382 |
f"<source src='{_file_url(webm)}' type='video/webm'>"
|
| 383 |
f"<source src='{_file_url(mp4)}' type='video/mp4'>"
|
| 384 |
"</video>"
|
|
@@ -640,6 +644,9 @@ def build_app() -> gr.Blocks:
|
|
| 640 |
gr.HTML(WHAT_HTML)
|
| 641 |
gr.HTML(emotion_html())
|
| 642 |
|
|
|
|
|
|
|
|
|
|
| 643 |
# -------- Live demo (keeps the working voice/chat loop) --------
|
| 644 |
gr.HTML(
|
| 645 |
"<section class='section' id='demo'>"
|
|
@@ -664,7 +671,6 @@ def build_app() -> gr.Blocks:
|
|
| 664 |
with gr.Row():
|
| 665 |
checkin_btn = gr.Button("☀️ Daily check-in", elem_classes="talk-btn")
|
| 666 |
|
| 667 |
-
gr.HTML(youtube_html())
|
| 668 |
gr.HTML(STACK_HTML)
|
| 669 |
gr.HTML(FIELD_NOTES_HTML)
|
| 670 |
gr.HTML(LEARNINGS_HTML)
|
|
|
|
| 376 |
|
| 377 |
|
| 378 |
def _alpha_video(webm: str, mp4: str, side_class: str, label: str) -> str:
|
| 379 |
+
# autoplay+muted+playsinline so it loops silently; preload=auto + an onloadeddata
|
| 380 |
+
# play() nudge so it starts even if the browser defers autoplay during load.
|
| 381 |
return (
|
| 382 |
f"<video class='hero-vid {side_class}' autoplay loop muted playsinline "
|
| 383 |
+
f"preload='auto' aria-label='{label}' "
|
| 384 |
+
"onloadeddata='this.play().catch(function(){});' "
|
| 385 |
+
"oncanplay='this.play().catch(function(){});'>"
|
| 386 |
f"<source src='{_file_url(webm)}' type='video/webm'>"
|
| 387 |
f"<source src='{_file_url(mp4)}' type='video/mp4'>"
|
| 388 |
"</video>"
|
|
|
|
| 644 |
gr.HTML(WHAT_HTML)
|
| 645 |
gr.HTML(emotion_html())
|
| 646 |
|
| 647 |
+
# Watch the demo first, then try it live.
|
| 648 |
+
gr.HTML(youtube_html())
|
| 649 |
+
|
| 650 |
# -------- Live demo (keeps the working voice/chat loop) --------
|
| 651 |
gr.HTML(
|
| 652 |
"<section class='section' id='demo'>"
|
|
|
|
| 671 |
with gr.Row():
|
| 672 |
checkin_btn = gr.Button("☀️ Daily check-in", elem_classes="talk-btn")
|
| 673 |
|
|
|
|
| 674 |
gr.HTML(STACK_HTML)
|
| 675 |
gr.HTML(FIELD_NOTES_HTML)
|
| 676 |
gr.HTML(LEARNINGS_HTML)
|