@import url('https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=DM+Mono:wght@400;500&family=Geist:wght@300;400;500;600&display=swap'); /* See the Tailwind configuration guide for advanced usage https://tailwindcss.com/docs/configuration */ @import "tailwindcss" source(none); @source "../../deps/ash_authentication_phoenix"; @source "../css"; @source "../js"; @source "../../lib/mixer_web"; /* A Tailwind plugin that makes "hero-#{ICON}" classes available. The heroicons installation itself is managed by your mix.exs */ @plugin "../vendor/heroicons"; /* daisyUI Tailwind Plugin. You can update this file by fetching the latest version with: curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui.js Make sure to look at the daisyUI changelog: https://daisyui.com/docs/changelog/ */ @plugin "../vendor/daisyui" { themes: false; } /* daisyUI theme plugin. You can update this file by fetching the latest version with: curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui-theme.js We ship with two themes, a light one inspired on Phoenix colors and a dark one inspired on Elixir colors. Build your own at: https://daisyui.com/theme-generator/ */ @plugin "../vendor/daisyui-theme" { name: "dark"; default: true; prefersdark: true; color-scheme: "dark"; --color-base-100: oklch(5% 0.005 270); --color-base-200: oklch(8% 0.005 270); --color-base-300: oklch(13% 0.008 270); --color-base-content: oklch(93% 0.006 270); --color-primary: oklch(58% 0.21 278); --color-primary-content: oklch(98% 0.01 278); --color-secondary: oklch(52% 0.18 278); --color-secondary-content: oklch(98% 0.01 278); --color-accent: oklch(68% 0.17 278); --color-accent-content: oklch(98% 0.01 278); --color-neutral: oklch(20% 0.012 270); --color-neutral-content: oklch(93% 0.006 270); --color-info: oklch(58% 0.158 241.966); --color-info-content: oklch(97% 0.013 236.62); --color-success: oklch(60% 0.118 184.704); --color-success-content: oklch(98% 0.014 180.72); --color-warning: oklch(66% 0.179 58.318); --color-warning-content: oklch(98% 0.022 95.277); --color-error: oklch(58% 0.253 17.585); --color-error-content: oklch(96% 0.015 12.422); --radius-selector: 0.5rem; --radius-field: 0.5rem; --radius-box: 0.75rem; --size-selector: 0.21875rem; --size-field: 0.21875rem; --border: 1px; --depth: 0; --noise: 0; } @plugin "../vendor/daisyui-theme" { name: "light"; default: false; prefersdark: false; color-scheme: "light"; --color-base-100: oklch(97% 0.003 270); --color-base-200: oklch(93% 0.005 270); --color-base-300: oklch(88% 0.007 270); --color-base-content: oklch(12% 0.008 270); --color-primary: oklch(58% 0.21 278); --color-primary-content: oklch(98% 0.01 278); --color-secondary: oklch(52% 0.18 278); --color-secondary-content: oklch(98% 0.01 278); --color-accent: oklch(68% 0.17 278); --color-accent-content: oklch(98% 0.01 278); --color-neutral: oklch(88% 0.007 270); --color-neutral-content: oklch(12% 0.008 270); --color-info: oklch(62% 0.214 259.815); --color-info-content: oklch(97% 0.014 254.604); --color-success: oklch(70% 0.14 182.503); --color-success-content: oklch(98% 0.014 180.72); --color-warning: oklch(66% 0.179 58.318); --color-warning-content: oklch(98% 0.022 95.277); --color-error: oklch(58% 0.253 17.585); --color-error-content: oklch(96% 0.015 12.422); --radius-selector: 0.5rem; --radius-field: 0.5rem; --radius-box: 0.75rem; --size-selector: 0.21875rem; --size-field: 0.21875rem; --border: 1px; --depth: 0; --noise: 0; } /* Add variants based on LiveView classes */ @custom-variant phx-click-loading (.phx-click-loading&, .phx-click-loading &); @custom-variant phx-submit-loading (.phx-submit-loading&, .phx-submit-loading &); @custom-variant phx-change-loading (.phx-change-loading&, .phx-change-loading &); /* Use the data attribute for dark mode */ @custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *)); /* Make LiveView wrapper divs transparent for layout */ [data-phx-session], [data-phx-teleported-src] { display: contents } /* ── Global base ── */ html, body { font-family: 'Geist', system-ui, sans-serif; } /* ── Mixer design tokens — mapped to daisyUI so they track the active theme ── */ :root { --mx-bg: var(--color-base-100); --mx-surface: var(--color-base-200); --mx-surface2: var(--color-base-300); --mx-fg: var(--color-base-content); --mx-accent: var(--color-primary); --mx-accent2: var(--color-accent); --mx-red: #ef4444; --mx-green: #22c55e; --mx-radius: 12px; --mx-radius-sm: 8px; } [data-theme=dark] { --mx-fg2: #9090a8; --mx-muted: #5a5a72; --mx-border: oklch(22% 0.010 270); --mx-border2: oklch(30% 0.012 270); } [data-theme=light] { --mx-fg2: #6060a0; --mx-muted: #9090b8; --mx-border: #d8d8e8; --mx-border2: #c0c0d8; } /* ── Mixer app shell ── */ #app { min-height: 100vh; } /* ── Layout ── */ .mx-root { display: grid; grid-template-columns: 240px 1fr 280px; min-height: 100vh; max-width: 1200px; margin: 0 auto; } @media (max-width: 960px) { .mx-root { grid-template-columns: 64px 1fr; } .mx-rightbar { display: none; } } @media (max-width: 640px) { .mx-root { grid-template-columns: 1fr; } .mx-sidebar { display: none; } } /* ── Sidebar ── */ .mx-sidebar { position: sticky; top: 0; height: 100vh; padding: 1.5rem 1rem; display: flex; flex-direction: column; border-right: 1px solid color-mix(in oklch, var(--color-base-content) 18%, transparent); } .mx-logo { display: flex; align-items: center; gap: 0.625rem; padding: 0.25rem 0.5rem; margin-bottom: 2rem; } .mx-logo-icon { font-size: 1.4rem; color: var(--mx-accent2); line-height: 1; } .mx-logo-text { font-family: 'Instrument Serif', Georgia, serif; font-size: 1.5rem; font-style: italic; color: var(--mx-fg); letter-spacing: -0.02em; } .mx-nav { display: flex; flex-direction: column; gap: 0.25rem; } .mx-nav-item { display: flex; align-items: center; gap: 0.75rem; padding: 0.625rem 0.75rem; border-radius: var(--mx-radius-sm); text-decoration: none; color: var(--mx-fg2); font-size: 1rem; font-weight: 500; cursor: pointer; transition: color 0.15s, background 0.15s, box-shadow 0.15s; } .mx-nav-item:hover { color: var(--mx-fg); background: var(--mx-surface2); box-shadow: inset 3px 0 0 var(--color-primary); } .mx-nav-active { color: var(--mx-fg) !important; background: color-mix(in oklch, var(--color-primary) 12%, transparent) !important; box-shadow: inset 3px 0 0 var(--color-primary) !important; } .mx-sidebar-footer { margin-top: auto; padding: 0.5rem; display: flex; flex-direction: column; gap: 0.5rem; } .mx-version { font-family: 'DM Mono', monospace; font-size: 0.7rem; color: var(--mx-muted); } .mx-auth-link { font-size: 0.75rem; color: var(--mx-accent2); text-decoration: none; transition: color 0.15s; } .mx-auth-link:hover { color: var(--mx-fg); } /* ── Main ── */ .mx-main { border-right: 1px solid color-mix(in oklch, var(--color-base-content) 18%, transparent); min-height: 100vh; } .mx-header { position: sticky; top: 0; z-index: 10; display: flex; align-items: center; justify-content: space-between; padding: 1rem 1.25rem; background: color-mix(in oklch, var(--mx-bg) 85%, transparent); backdrop-filter: blur(12px); border-bottom: 1px solid var(--mx-border); } .mx-header-title { font-family: 'Instrument Serif', Georgia, serif; font-size: 1.25rem; font-style: italic; font-weight: 400; color: var(--mx-fg); letter-spacing: -0.02em; } .mx-refresh-btn { background: none; border: 1px solid var(--mx-border2); color: var(--mx-fg2); width: 32px; height: 32px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: color 0.15s, border-color 0.15s; } .mx-refresh-btn:hover { color: var(--mx-fg); border-color: var(--mx-accent); } .mx-divider { height: 1px; background: color-mix(in oklch, var(--color-base-content) 18%, transparent); } /* ── Compose ── */ .mx-compose-wrapper { padding: 1rem 1.25rem; } .mx-compose { display: flex; gap: 0.75rem; } .mx-compose-avatar, .mx-tweet-avatar { width: 38px; height: 38px; border-radius: 50%; background: linear-gradient(135deg, var(--mx-accent) 0%, var(--mx-accent2) 100%); display: flex; align-items: center; justify-content: center; font-size: 0.8rem; font-weight: 600; color: white; flex-shrink: 0; user-select: none; } .mx-compose-body { flex: 1; } .mx-compose-textarea, .mx-edit-textarea { width: 100%; background: transparent; border: none; outline: none; color: var(--mx-fg); font-family: 'Geist', system-ui, sans-serif; font-size: 1.0625rem; resize: none; overflow: hidden; line-height: 1.55; padding: 0.375rem 0; } .mx-compose-textarea::placeholder { color: var(--mx-muted); } .mx-compose-footer { display: flex; align-items: center; justify-content: space-between; margin-top: 0.5rem; padding-top: 0.5rem; border-top: 1px solid var(--mx-border); } .mx-compose-hint { font-size: 0.7rem; color: var(--mx-muted); font-family: 'DM Mono', monospace; } .mx-compose-actions { display: flex; align-items: center; gap: 0.75rem; } .mx-compose-error { font-size: 0.75rem; color: var(--mx-red); margin-top: 0.25rem; } .mx-signin-cta { padding: 1.25rem; text-align: center; border-bottom: 1px solid var(--mx-border); } .mx-signin-cta p { font-size: 0.875rem; color: var(--mx-fg2); margin-bottom: 0.75rem; } .mx-btn-post, .mx-btn-save { background: var(--mx-accent); color: white; border: none; border-radius: 99px; padding: 0.375rem 1rem; font-size: 0.8125rem; font-weight: 600; cursor: pointer; transition: background 0.15s, opacity 0.15s, box-shadow 0.15s; font-family: inherit; text-decoration: none; box-shadow: 0 0 0 1px color-mix(in oklch, var(--color-primary) 60%, transparent); } .mx-btn-post:hover, .mx-btn-save:hover { background: var(--mx-accent2); box-shadow: 0 0 0 1px color-mix(in oklch, var(--color-accent) 80%, transparent); } .mx-btn-post:disabled, .mx-btn-save:disabled { opacity: 0.5; cursor: not-allowed; } .mx-btn-cancel { background: none; border: 1px solid var(--mx-fg2); color: var(--mx-fg2); border-radius: 99px; padding: 0.375rem 0.875rem; font-size: 0.8125rem; cursor: pointer; transition: color 0.15s, border-color 0.15s; font-family: inherit; } .mx-btn-cancel:hover { color: var(--mx-fg); border-color: var(--mx-fg2); } /* ── Feed ── */ .mx-feed { display: flex; flex-direction: column; gap: 0.75rem; padding: 1rem 1.25rem; } /* ── Tweet Card ── */ .mx-tweet { display: flex; gap: 0.75rem; padding: 1rem 1.25rem; border: 1px solid var(--mx-border); border-radius: var(--mx-radius); background: var(--mx-surface); transition: background 0.1s, border-color 0.1s; animation: mx-fade-in 0.2s ease; } .mx-tweet:hover { background: var(--mx-surface2); border-color: var(--mx-border2); } @keyframes mx-fade-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } } .mx-tweet-body { flex: 1; min-width: 0; } .mx-tweet-header { display: flex; align-items: center; gap: 0.375rem; margin-bottom: 0.375rem; } .mx-tweet-handle { font-size: 0.9375rem; font-weight: 600; color: var(--mx-fg); } .mx-tweet-dot, .mx-tweet-time { font-size: 0.8rem; color: var(--mx-muted); } .mx-tweet-actions { margin-left: auto; display: flex; gap: 0.125rem; opacity: 0.25; transition: opacity 0.15s; } .mx-tweet:hover .mx-tweet-actions { opacity: 1; } .mx-action-btn { background: none; border: none; color: var(--mx-muted); cursor: pointer; width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: color 0.15s, background 0.15s; } .mx-action-btn:hover { color: var(--mx-fg); background: var(--mx-surface2); } .mx-action-delete:hover { color: var(--mx-red); background: color-mix(in oklch, var(--mx-red) 10%, transparent); } .mx-action-confirm { color: var(--mx-red) !important; background: color-mix(in oklch, var(--mx-red) 15%, transparent) !important; } .mx-tweet-text { font-size: 1rem; line-height: 1.6; color: var(--mx-fg); white-space: pre-wrap; word-break: break-word; } .mx-tweet-footer { display: flex; align-items: center; margin-top: 0.875rem; } .mx-like-btn { display: inline-flex; align-items: center; gap: 0.45rem; border: 1px solid var(--mx-border2); border-radius: 999px; background: color-mix(in oklch, var(--mx-surface2) 72%, transparent); color: var(--mx-fg2); cursor: pointer; font-family: 'DM Mono', monospace; font-size: 0.75rem; line-height: 1; padding: 0.45rem 0.75rem; transition: transform 0.15s, border-color 0.15s, color 0.15s, background 0.15s; } .mx-like-btn:hover:not(:disabled) { color: var(--mx-red); border-color: color-mix(in oklch, var(--mx-red) 35%, transparent); background: color-mix(in oklch, var(--mx-red) 10%, transparent); transform: translateY(-1px); } .mx-like-btn:disabled { cursor: not-allowed; opacity: 0.6; } .mx-like-btn-active { color: var(--mx-red); border-color: color-mix(in oklch, var(--mx-red) 35%, transparent); background: color-mix(in oklch, var(--mx-red) 12%, transparent); } /* ── Edit ── */ .mx-edit-area { margin-top: 0.25rem; } .mx-edit-textarea { border: 1px solid var(--mx-border2); border-radius: var(--mx-radius-sm); padding: 0.5rem 0.75rem; background: var(--mx-surface2); width: 100%; overflow: auto; } .mx-edit-textarea:focus { border-color: var(--mx-accent); outline: none; } .mx-edit-footer { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.5rem; } /* ── Empty state ── */ .mx-empty { display: flex; flex-direction: column; align-items: center; padding: 4rem 2rem; text-align: center; } .mx-empty-icon { font-size: 2.5rem; color: var(--mx-muted); margin-bottom: 1rem; opacity: 0.5; } .mx-empty-title { font-family: 'Instrument Serif', serif; font-style: italic; font-size: 1.25rem; color: var(--mx-fg2); margin-bottom: 0.375rem; } .mx-empty-sub { font-size: 0.875rem; color: var(--mx-muted); } /* ── Spinner ── */ .mx-spinner { width: 22px; height: 22px; border: 2px solid var(--mx-border2); border-top-color: var(--mx-accent); border-radius: 50%; animation: mx-spin 0.7s linear infinite; } @keyframes mx-spin { to { transform: rotate(360deg); } } /* ── Error banner ── */ .mx-error-banner { display: flex; align-items: center; gap: 0.5rem; margin: 1rem 1.25rem; padding: 0.75rem 1rem; background: color-mix(in oklch, var(--mx-red) 8%, transparent); border: 1px solid color-mix(in oklch, var(--mx-red) 25%, transparent); border-radius: var(--mx-radius-sm); color: color-mix(in oklch, var(--mx-red) 70%, white); font-size: 0.875rem; } .mx-error-icon { font-size: 1rem; } /* ── Right bar ── */ .mx-rightbar { padding: 1.25rem; } .mx-info-card { background: var(--mx-surface); border: 1px solid var(--mx-border); border-radius: var(--mx-radius); padding: 1rem; } .mx-info-title { font-size: 0.875rem; font-weight: 600; color: var(--mx-fg); margin-bottom: 0.5rem; } .mx-info-body { font-size: 0.8125rem; color: var(--mx-fg2); line-height: 1.5; margin-bottom: 0.875rem; } .mx-stack { display: flex; flex-wrap: wrap; gap: 0.375rem; } .mx-tag { font-family: 'DM Mono', monospace; font-size: 0.65rem; padding: 0.25rem 0.5rem; border-radius: 4px; background: var(--mx-surface2); border: 1px solid var(--mx-border2); color: var(--mx-accent2); } /* ── Tweet Detail Page ── */ .mx-detail { padding: 1rem 1.5rem; } .mx-detail-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.5rem; } .mx-back-btn { display: inline-flex; align-items: center; gap: 0.4rem; color: var(--mx-fg2); font-size: 0.85rem; text-decoration: none; padding: 0.4rem 0.75rem; border-radius: var(--mx-radius-sm); border: 1px solid var(--mx-border); transition: background 0.15s; } .mx-back-btn:hover { background: var(--mx-surface2); } .mx-detail-author { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1rem; } .mx-detail-body { padding: 0.5rem 0; } .mx-detail-content { font-size: 1.1rem; line-height: 1.6; color: var(--mx-fg); margin-bottom: 1rem; white-space: pre-wrap; word-break: break-word; } .mx-detail-media { display: flex; flex-direction: column; gap: 0.75rem; margin-bottom: 1rem; } /* ── Clickable media thumb (used in detail view) ── */ .mx-media-thumb { background: none; border: none; padding: 0; cursor: pointer; border-radius: var(--mx-radius-sm); overflow: hidden; display: block; width: 100%; } .mx-media-thumb img, .mx-media-thumb video { width: 100%; border-radius: var(--mx-radius-sm); display: block; } .mx-media-thumb:hover { opacity: 0.85; } /* ── Media Lightbox ── */ .mx-lightbox { position: fixed; inset: 0; z-index: 200; background: rgba(0, 0, 0, 0.92); display: flex; align-items: center; justify-content: center; } .mx-lightbox-close { position: absolute; top: 1rem; right: 1rem; background: rgba(255, 255, 255, 0.1); border: none; color: #fff; cursor: pointer; font-size: 1.1rem; width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; } .mx-lightbox-close:hover { background: rgba(255, 255, 255, 0.2); } .mx-lightbox-content { max-width: 90vw; max-height: 90vh; } .mx-lightbox-media { max-width: 90vw; max-height: 90vh; border-radius: var(--mx-radius-sm); display: block; }