/* See the Tailwind configuration guide for advanced usage https://tailwindcss.com/docs/configuration */ @import "tailwindcss" source(none); @source "../css"; @source "../js"; @source "../../lib/firehose_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; } /* Warm light theme — amber/terracotta + cream */ @plugin "../vendor/daisyui-theme" { name: "light"; default: true; prefersdark: false; color-scheme: "light"; --color-base-100: oklch(97% 0.008 75); --color-base-200: oklch(94% 0.012 75); --color-base-300: oklch(90% 0.016 75); --color-base-content: oklch(25% 0.015 50); --color-primary: oklch(58% 0.16 45); --color-primary-content: oklch(98% 0.01 75); --color-secondary: oklch(55% 0.12 30); --color-secondary-content: oklch(98% 0.008 30); --color-accent: oklch(62% 0.19 55); --color-accent-content: oklch(98% 0.01 55); --color-neutral: oklch(40% 0.02 50); --color-neutral-content: oklch(97% 0.005 75); --color-info: oklch(62% 0.17 245); --color-info-content: oklch(97% 0.01 245); --color-success: oklch(65% 0.15 155); --color-success-content: oklch(98% 0.01 155); --color-warning: oklch(72% 0.16 70); --color-warning-content: oklch(25% 0.02 70); --color-error: oklch(58% 0.22 25); --color-error-content: oklch(97% 0.01 25); --radius-selector: 0.375rem; --radius-field: 0.375rem; --radius-box: 0.75rem; --size-selector: 0.25rem; --size-field: 0.25rem; --border: 1px; --depth: 1; --noise: 0; } /* Warm dark theme */ @plugin "../vendor/daisyui-theme" { name: "dark"; default: false; prefersdark: true; color-scheme: "dark"; --color-base-100: oklch(24% 0.015 50); --color-base-200: oklch(20% 0.012 50); --color-base-300: oklch(16% 0.01 50); --color-base-content: oklch(92% 0.015 75); --color-primary: oklch(68% 0.16 45); --color-primary-content: oklch(18% 0.02 45); --color-secondary: oklch(62% 0.12 30); --color-secondary-content: oklch(18% 0.01 30); --color-accent: oklch(70% 0.17 55); --color-accent-content: oklch(18% 0.01 55); --color-neutral: oklch(32% 0.02 50); --color-neutral-content: oklch(92% 0.008 75); --color-info: oklch(62% 0.17 245); --color-info-content: oklch(97% 0.01 245); --color-success: oklch(65% 0.15 155); --color-success-content: oklch(98% 0.01 155); --color-warning: oklch(72% 0.16 70); --color-warning-content: oklch(25% 0.02 70); --color-error: oklch(58% 0.22 25); --color-error-content: oklch(97% 0.01 25); --radius-selector: 0.375rem; --radius-field: 0.375rem; --radius-box: 0.75rem; --size-selector: 0.25rem; --size-field: 0.25rem; --border: 1px; --depth: 1; --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 } /* Self-hosted fonts — no external requests */ @font-face { font-family: 'Fraunces'; font-style: normal; font-weight: 300 900; font-display: swap; src: url(/fonts/fraunces.woff2) format('woff2'); } @font-face { font-family: 'Fraunces'; font-style: italic; font-weight: 300 900; font-display: swap; src: url(/fonts/fraunces-italic.woff2) format('woff2'); } @font-face { font-family: 'Source Sans 3'; font-style: normal; font-weight: 300 900; font-display: swap; src: url(/fonts/sourcesans3.woff2) format('woff2'); } @font-face { font-family: 'Source Sans 3'; font-style: italic; font-weight: 300 900; font-display: swap; src: url(/fonts/sourcesans3-italic.woff2) format('woff2'); } /* Typography */ .font-display { font-family: 'Fraunces', serif; } body { font-family: 'Source Sans 3', sans-serif; } /* Blogex component styling */ .blogex-post-index { display: flex; flex-direction: column; gap: 1.5rem; } .blogex-post-preview header h2 { font-family: 'Fraunces', serif; font-size: 1.25rem; font-weight: 600; } .blogex-post-preview header h2 a { color: oklch(var(--color-base-content)); text-decoration: none; } .blogex-post-preview header h2 a:hover { color: oklch(var(--color-primary)); } .blogex-post-description { margin-top: 0.25rem; opacity: 0.7; } .blogex-post-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; font-size: 0.875rem; opacity: 0.6; margin-top: 0.25rem; } .blogex-tag { display: inline-block; padding: 0.125rem 0.5rem; border-radius: 9999px; font-size: 0.75rem; background: oklch(var(--color-base-200)); } .blogex-post-header h1 { font-family: 'Fraunces', serif; font-size: 2rem; font-weight: 700; line-height: 1.2; } .blogex-post-body { margin-top: 2rem; line-height: 1.75; } .blogex-post-body h1 { font-family: 'Fraunces', serif; font-size: 1.75rem; font-weight: 700; margin-top: 2.5rem; margin-bottom: 0.5rem; } .blogex-post-body h2 { font-family: 'Fraunces', serif; font-size: 1.5rem; font-weight: 600; margin-top: 2rem; margin-bottom: 0.5rem; } .blogex-post-body h3 { font-family: 'Fraunces', serif; font-size: 1.25rem; font-weight: 600; margin-top: 1.5rem; margin-bottom: 0.5rem; } .blogex-post-body p { margin-top: 1rem; } .blogex-post-body ul { list-style: disc; padding-left: 1.5rem; margin-top: 0.5rem; } .blogex-post-body ol { list-style: decimal; padding-left: 1.5rem; margin-top: 0.5rem; } .blogex-post-body pre { background: oklch(var(--color-base-200)); padding: 1rem; border-radius: 0.5rem; overflow-x: auto; margin-top: 1rem; } .blogex-post-body code { font-size: 0.875em; } .blogex-post-body a { color: oklch(var(--color-primary)); text-decoration: underline; } .blogex-post-body blockquote { border-left: 3px solid oklch(var(--color-primary)); padding-left: 1rem; margin-top: 1rem; margin-bottom: 1rem; font-style: italic; opacity: 0.85; } .blogex-tag-list { display: flex; flex-wrap: wrap; gap: 0.5rem; } .blogex-tag-link { display: inline-block; padding: 0.25rem 0.75rem; border-radius: 9999px; font-size: 0.875rem; background: oklch(var(--color-base-200)); text-decoration: none; } .blogex-tag-link:hover, .blogex-tag-active { background: oklch(var(--color-primary)); color: oklch(var(--color-primary-content)); } .blogex-pagination { display: flex; align-items: center; justify-content: center; gap: 1rem; padding-top: 1rem; font-size: 0.875rem; } .blogex-pagination a { color: oklch(var(--color-primary)); text-decoration: none; } .blogex-pagination a:hover { text-decoration: underline; } /* Source Viewer — line-numbered code display */ .source-viewer { --sv-bg: oklch(20.15% 0.012 254.09); --sv-text: oklch(90% 0.01 240); --sv-line-num: oklch(55% 0.02 240); --sv-highlight: oklch(30% 0.02 240); } [data-theme="dark"] .source-viewer { --sv-bg: oklch(16% 0.01 254); --sv-text: oklch(88% 0.01 240); --sv-line-num: oklch(50% 0.02 240); --sv-highlight: oklch(25% 0.02 240); } .sv-lines { display: flex; flex-direction: column; } .sv-line { display: flex; align-items: baseline; min-height: 1.25rem; padding: 0 0.25rem; transition: background-color 0.2s ease; } .sv-line-highlighted { background-color: var(--sv-highlight); } .sv-line-number { display: inline-block; width: 2.5rem; text-align: right; padding-right: 0.75rem; color: var(--sv-line-num); user-select: none; opacity: 0.6; flex-shrink: 0; } .sv-line-content { white-space: pre; flex: 1; min-width: 0; } /* highlight.js — Atom One Dark (dark theme) */ .source-viewer code.hljs { color: #abb2bf; background: transparent; padding: 0; } .source-viewer code.hljs .hljs-comment, .source-viewer code.hljs .hljs-quote { color: #5c6370; font-style: italic; } .source-viewer code.hljs .hljs-doctag, .source-viewer code.hljs .hljs-keyword, .source-viewer code.hljs .hljs-formula { color: #c678dd; } .source-viewer code.hljs .hljs-section, .source-viewer code.hljs .hljs-name, .source-viewer code.hljs .hljs-selector-tag, .source-viewer code.hljs .hljs-deletion, .source-viewer code.hljs .hljs-subst { color: #e06c75; } .source-viewer code.hljs .hljs-literal { color: #56b6c2; } .source-viewer code.hljs .hljs-string, .source-viewer code.hljs .hljs-regexp, .source-viewer code.hljs .hljs-addition, .source-viewer code.hljs .hljs-attribute, .source-viewer code.hljs .hljs-meta .hljs-string { color: #98c379; } .source-viewer code.hljs .hljs-attr, .source-viewer code.hljs .hljs-variable, .source-viewer code.hljs .hljs-template-variable, .source-viewer code.hljs .hljs-type, .source-viewer code.hljs .hljs-selector-class, .source-viewer code.hljs .hljs-selector-attr, .source-viewer code.hljs .hljs-selector-pseudo, .source-viewer code.hljs .hljs-number { color: #d19a66; } .source-viewer code.hljs .hljs-symbol, .source-viewer code.hljs .hljs-link, .source-viewer code.hljs .hljs-meta, .source-viewer code.hljs .hljs-selector-id, .source-viewer code.hljs .hljs-title { color: #61aeee; } .source-viewer code.hljs .hljs-built_in, .source-viewer code.hljs .hljs-title.class_, .source-viewer code.hljs .hljs-class .hljs-title { color: #e6c07b; } .source-viewer code.hljs .hljs-emphasis { font-style: italic; } .source-viewer code.hljs .hljs-strong { font-weight: bold; } /* highlight.js — Atom One Light (light theme) */ [data-theme="light"] .source-viewer code.hljs { color: #383a42; background: transparent; } [data-theme="light"] .source-viewer code.hljs .hljs-comment, [data-theme="light"] .source-viewer code.hljs .hljs-quote { color: #a0a1a7; font-style: italic; } [data-theme="light"] .source-viewer code.hljs .hljs-doctag, [data-theme="light"] .source-viewer code.hljs .hljs-keyword, [data-theme="light"] .source-viewer code.hljs .hljs-formula { color: #a626a4; } [data-theme="light"] .source-viewer code.hljs .hljs-section, [data-theme="light"] .source-viewer code.hljs .hljs-name, [data-theme="light"] .source-viewer code.hljs .hljs-selector-tag, [data-theme="light"] .source-viewer code.hljs .hljs-deletion, [data-theme="light"] .source-viewer code.hljs .hljs-subst { color: #e45649; } [data-theme="light"] .source-viewer code.hljs .hljs-literal { color: #0184bc; } [data-theme="light"] .source-viewer code.hljs .hljs-string, [data-theme="light"] .source-viewer code.hljs .hljs-regexp, [data-theme="light"] .source-viewer code.hljs .hljs-addition, [data-theme="light"] .source-viewer code.hljs .hljs-attribute, [data-theme="light"] .source-viewer code.hljs .hljs-meta .hljs-string { color: #50a14f; } [data-theme="light"] .source-viewer code.hljs .hljs-attr, [data-theme="light"] .source-viewer code.hljs .hljs-variable, [data-theme="light"] .source-viewer code.hljs .hljs-template-variable, [data-theme="light"] .source-viewer code.hljs .hljs-type, [data-theme="light"] .source-viewer code.hljs .hljs-selector-class, [data-theme="light"] .source-viewer code.hljs .hljs-selector-attr, [data-theme="light"] .source-viewer code.hljs .hljs-selector-pseudo, [data-theme="light"] .source-viewer code.hljs .hljs-number { color: #986801; } [data-theme="light"] .source-viewer code.hljs .hljs-symbol, [data-theme="light"] .source-viewer code.hljs .hljs-link, [data-theme="light"] .source-viewer code.hljs .hljs-meta, [data-theme="light"] .source-viewer code.hljs .hljs-selector-id, [data-theme="light"] .source-viewer code.hljs .hljs-title { color: #4078f2; } [data-theme="light"] .source-viewer code.hljs .hljs-built_in, [data-theme="light"] .source-viewer code.hljs .hljs-title.class_, [data-theme="light"] .source-viewer code.hljs .hljs-class .hljs-title { color: #c18401; } [data-theme="light"] .source-viewer code.hljs .hljs-emphasis { font-style: italic; } [data-theme="light"] .source-viewer code.hljs .hljs-strong { font-weight: bold; }