Deployment (t4g2): media-worker gains font-dejavu (drawtext lower-thirds) and a dedicated produce-worker compose service running src/produce.ts — claims video_processing_jobs compose|mix by lane, renders assembled/ overlaid/voiced cuts, registers derived library assets. Deliberately its own process so a remote-lane box needs only Postgres + S3 + ffmpeg. Web: compose media attachments UI (t2), Producer panel in the video drawer (t5), collective creation + branding settings + shell branding (brandweb), mobile CSS (mcss: touch targets, icon sizing, safe areas).
190 lines
6.4 KiB
CSS
190 lines
6.4 KiB
CSS
@import "tailwindcss";
|
||
|
||
@theme {
|
||
--color-bg: oklch(0.11 0.008 25);
|
||
--color-surface: oklch(0.15 0.01 25);
|
||
--color-surface-2: oklch(0.19 0.012 25);
|
||
--color-border: oklch(0.26 0.02 25);
|
||
--color-border-subtle: oklch(0.22 0.015 25);
|
||
--color-text: oklch(0.93 0.005 25);
|
||
--color-text-dim: oklch(0.62 0.02 25);
|
||
--color-text-faint: oklch(0.46 0.02 25);
|
||
--color-accent: #ff1610;
|
||
--color-accent-hover: #e3130e;
|
||
--color-accent-dim: rgb(255 22 16 / 0.15);
|
||
--color-live: oklch(0.72 0.19 145);
|
||
--color-warn: oklch(0.78 0.16 85);
|
||
--color-danger: oklch(0.55 0.24 15);
|
||
--color-added: oklch(0.72 0.16 145);
|
||
--color-removed: oklch(0.55 0.24 15);
|
||
|
||
--font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
||
--font-mono: ui-monospace, "SF Mono", Menlo, monospace;
|
||
|
||
--radius-sm: 0.375rem;
|
||
--radius-md: 0.5rem;
|
||
--radius-lg: 0.75rem;
|
||
|
||
--text-2xs: 0.6875rem;
|
||
--text-xs: 0.75rem;
|
||
--text-sm: 0.8125rem;
|
||
--text-base: 0.875rem;
|
||
--text-lg: 1rem;
|
||
|
||
--mobile-tab-height: 76px;
|
||
--mobile-fab-size: 64px;
|
||
--mobile-sheet-radius: 28px;
|
||
--mobile-safe-bottom: env(safe-area-inset-bottom, 0px);
|
||
}
|
||
|
||
@theme inline {
|
||
--color-brand: var(--color-accent);
|
||
}
|
||
|
||
html {
|
||
color-scheme: dark;
|
||
}
|
||
|
||
body {
|
||
background: var(--color-bg);
|
||
color: var(--color-text);
|
||
font-family: var(--font-sans);
|
||
font-size: var(--text-base);
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
html, body { max-width: 100%; }
|
||
|
||
@media (max-width: 1023px) {
|
||
body { overflow-x: hidden; }
|
||
[data-mobile-main] :is(button, a[href], input, select, textarea, [role="tab"]) {
|
||
min-height: 44px;
|
||
}
|
||
[data-mobile-main] :is(button, a[href], [role="tab"]) {
|
||
min-width: 44px;
|
||
}
|
||
[data-mobile-main] p a[href] { display: inline-flex; align-items: center; }
|
||
[data-mobile-main] .mobile-stack-table,
|
||
[data-mobile-main] .mobile-stack-table tbody,
|
||
[data-mobile-main] .mobile-stack-table tr,
|
||
[data-mobile-main] .mobile-stack-table td { display: block; width: 100%; min-width: 0; }
|
||
[data-mobile-main] .mobile-stack-table thead { display: none; }
|
||
[data-mobile-main] .mobile-stack-table tr { padding: 8px 0; }
|
||
[data-mobile-main] .mobile-stack-table td { overflow-wrap: anywhere; }
|
||
[data-mobile-main] .mobile-stack-table td > * { max-width: 100%; }
|
||
}
|
||
|
||
/* ---------------------------------------------------------------------------
|
||
Phone tier (≤640px) — native feel, touch targets, safe areas, overflow.
|
||
Scoped globally (body-wide) rather than to [data-mobile-main] because the
|
||
auth screens (/login, /signup, /join, /submit, /oidc) and the body-portal
|
||
sheets render outside the main shell and were getting none of this.
|
||
These rules are unlayered, so they outrank Tailwind's `@layer utilities`
|
||
without needing !important.
|
||
--------------------------------------------------------------------------- */
|
||
@media (max-width: 640px) {
|
||
/* -- Native feel: no tap highlight flash, no double-tap-zoom delay on
|
||
controls (pinch zoom stays available — `manipulation` only disables
|
||
the double-tap gesture), no iOS landscape text inflation, no document
|
||
rubber-band behind the app shell. -- */
|
||
html {
|
||
-webkit-text-size-adjust: 100%;
|
||
text-size-adjust: 100%;
|
||
overscroll-behavior: none;
|
||
overflow-x: hidden;
|
||
}
|
||
body {
|
||
max-width: 100%;
|
||
overflow-x: hidden;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
body :where(button, a[href], [role="tab"], [role="button"], [role="switch"]) {
|
||
touch-action: manipulation;
|
||
}
|
||
|
||
/* -- ≥44px touch targets for buttons / icon-buttons (glyph buttons here are
|
||
plain <button>, bottom-nav tabs are <a>, segmented control is role=tab,
|
||
sheet drag handle is role=button). min-width is limited to controls that
|
||
are already box-shaped so inline text links keep their flow shape. -- */
|
||
body :where(button, a[href], [role="tab"], [role="button"], [role="switch"]) {
|
||
min-height: 44px;
|
||
}
|
||
body :where(nav button, nav a[href], [role="tab"]) {
|
||
min-width: 44px;
|
||
}
|
||
|
||
/* -- 16px minimum on text-entry controls: iOS Safari auto-zooms the viewport
|
||
on focus whenever the field's computed font-size is under 16px, which
|
||
reads as janky/non-native. Non-text inputs excluded (their size is
|
||
visual, not textual). -- */
|
||
body :where(
|
||
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="button"]):not([type="submit"]):not([type="reset"]),
|
||
select,
|
||
textarea
|
||
) {
|
||
font-size: 16px;
|
||
}
|
||
|
||
/* -- Icon sizing. Icons size via width/height attributes from React props,
|
||
not a CSS variable or utility class — but HTML sizing attributes are
|
||
presentational hints, so author CSS still wins without touching TSX.
|
||
Bottom-nav glyph: 24px → 22px (target band 20–22px; top of band keeps
|
||
it clearest at phone density). Inline SVG icons: ≥16px floor so the
|
||
14px spinners and 11px arrow glyphs stop rendering sub-legibly. -- */
|
||
nav[aria-label="Primary navigation"] img {
|
||
width: 22px;
|
||
height: 22px;
|
||
}
|
||
body :where(svg) {
|
||
min-width: 16px;
|
||
min-height: 16px;
|
||
}
|
||
|
||
/* -- Safe areas. Bottom is already covered app-wide via --mobile-safe-bottom
|
||
(bottom nav, sheets, compose's fixed action bar). This adds the other
|
||
three edges on the shell column that holds top bar + main + bottom nav
|
||
— the notch/home-indicator sides that only bite in landscape.
|
||
max() keeps the value at 0 on devices without insets, and degrades to
|
||
no padding at all on browsers without :has(). -- */
|
||
:has(> main[data-mobile-main]) {
|
||
padding-top: max(0px, env(safe-area-inset-top, 0px));
|
||
padding-left: max(0px, env(safe-area-inset-left, 0px));
|
||
padding-right: max(0px, env(safe-area-inset-right, 0px));
|
||
}
|
||
|
||
/* -- Horizontal overflow guards: belt-and-braces on the scroller plus a
|
||
cap on replaced media, the classic cause of stray phone scroll. -- */
|
||
main[data-mobile-main] {
|
||
max-width: 100%;
|
||
}
|
||
body :where(img, video, canvas, iframe, svg) {
|
||
max-width: 100%;
|
||
}
|
||
}
|
||
|
||
::selection {
|
||
background: var(--color-accent-dim);
|
||
}
|
||
|
||
:focus-visible {
|
||
outline: 2px solid var(--color-accent);
|
||
outline-offset: 1px;
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
transition-duration: 0.01ms !important;
|
||
animation-duration: 0.01ms !important;
|
||
}
|
||
}
|
||
|
||
.scrollbar-thin::-webkit-scrollbar {
|
||
width: 6px;
|
||
height: 6px;
|
||
}
|
||
.scrollbar-thin::-webkit-scrollbar-thumb {
|
||
background: var(--color-border);
|
||
border-radius: 3px;
|
||
}
|