Initial commit on Forgejo
Fresh repository history for elektrine/tarakan hosted at https://git.elektrine.com/elektrine/tarakan.
This commit is contained in:
commit
af6077b9c3
455 changed files with 78366 additions and 0 deletions
377
assets/css/app.css
Normal file
377
assets/css/app.css
Normal file
|
|
@ -0,0 +1,377 @@
|
|||
@import "tailwindcss" source(none);
|
||||
@import "phoenix-colocated/tarakan/colocated.css";
|
||||
@source "../css";
|
||||
@source "../js";
|
||||
@source "../../lib/tarakan_web";
|
||||
@source "../../_build/dev/phoenix-colocated/tarakan/*/";
|
||||
|
||||
@plugin "../vendor/heroicons";
|
||||
|
||||
@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 &);
|
||||
|
||||
[data-phx-session],
|
||||
[data-phx-teleported-src] {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
/* Tailwind's preflight leaves native buttons on the default arrow cursor.
|
||||
Make the interaction contract consistent without repeating cursor utilities
|
||||
on every component and LiveView action. */
|
||||
@layer base {
|
||||
html {
|
||||
-webkit-text-size-adjust: 100%;
|
||||
text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow-x: clip;
|
||||
}
|
||||
|
||||
/* Prefer larger tap targets on coarse pointers without changing desktop. */
|
||||
@media (pointer: coarse) {
|
||||
button:not(:disabled),
|
||||
a,
|
||||
summary,
|
||||
[role="button"] {
|
||||
touch-action: manipulation;
|
||||
}
|
||||
}
|
||||
|
||||
button:not(:disabled),
|
||||
input:is([type="button"], [type="submit"], [type="reset"]):not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:disabled,
|
||||
input:is([type="button"], [type="submit"], [type="reset"]):disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
/* Chakra Petch (400/500/700), latin subset, vendored in priv/static/fonts */
|
||||
@font-face {
|
||||
font-family: "Chakra Petch";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("/fonts/chakra-petch-latin-400.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Chakra Petch";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("/fonts/chakra-petch-latin-500.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Chakra Petch";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("/fonts/chakra-petch-latin-700.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* Tarakan color tokens.
|
||||
|
||||
Dark (flagship): pure void black, hard white type, signal red for findings
|
||||
and primary actions, amber for secondary callouts. Borders stay cold grey so
|
||||
red only hits where it means something (findings, CTAs, live pulse).
|
||||
Light: clinical paper, black ink, the same pure red under control. */
|
||||
:root {
|
||||
--ground: #f4f4f4;
|
||||
--panel: #ebebeb;
|
||||
--ink: #0a0a0a;
|
||||
--ink-muted: #444444;
|
||||
/* --ink-faint carries real telemetry (SHAs, timestamps, run counts) at 10-11px,
|
||||
so it has to clear WCAG AA against BOTH --ground and --panel, not just --ground.
|
||||
#666 = 5.2:1 on ground, 4.8:1 on panel. The old #777 was 4.1:1 / 3.8:1. */
|
||||
--ink-faint: #666666;
|
||||
--rule: #cccccc;
|
||||
--strong: #111111;
|
||||
--signal: #c40018;
|
||||
--quote: #9a6b00;
|
||||
--btn: #c40018;
|
||||
--btn-fg: #ffffff;
|
||||
/* The well is the surface live values sit on. Light keeps it visually flush
|
||||
with the ground - a dark slab reads as a defect on paper - but it must be
|
||||
an opaque paint, not transparent: wire-badge hollows fill with --well and
|
||||
would otherwise expose the badge's own stroke color. Dark gets the true
|
||||
phosphor treatment: recessed slab, scanlines, glow. */
|
||||
--well: #f4f4f4;
|
||||
--well-pad: 0;
|
||||
--phosphor: #c40018;
|
||||
--glow: none;
|
||||
--glow-soft: none;
|
||||
--scan: none;
|
||||
--live-edge: var(--signal);
|
||||
}
|
||||
|
||||
/* Dark tokens apply via OS preference, and via the manual toggle
|
||||
(data-theme). Keep the two dark blocks identical. */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme="light"]) {
|
||||
--ground: #000000;
|
||||
--panel: #0a0a0a;
|
||||
--ink: #f2f2f2;
|
||||
--ink-muted: #9a9a9a;
|
||||
--ink-faint: #7d7d7d;
|
||||
--rule: #1a1a1a;
|
||||
--strong: #2e2e2e;
|
||||
--signal: #e60012;
|
||||
--quote: #ffcc00;
|
||||
--btn: #e60012;
|
||||
--btn-fg: #ffffff;
|
||||
--well: #050505;
|
||||
--well-pad: 0.75rem;
|
||||
--phosphor: #ff1a2e;
|
||||
--live-edge: transparent;
|
||||
--glow: 0 0 12px color-mix(in srgb, var(--signal) 55%, transparent);
|
||||
--glow-soft: 0 0 8px color-mix(in srgb, var(--signal) 40%, transparent);
|
||||
--scan: repeating-linear-gradient(
|
||||
0deg,
|
||||
rgb(255 255 255 / 0.03) 0 1px,
|
||||
transparent 1px 3px
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] {
|
||||
--ground: #000000;
|
||||
--panel: #0a0a0a;
|
||||
--ink: #f2f2f2;
|
||||
--ink-muted: #9a9a9a;
|
||||
--ink-faint: #7d7d7d;
|
||||
--rule: #1a1a1a;
|
||||
--strong: #2e2e2e;
|
||||
--signal: #e60012;
|
||||
--quote: #ffcc00;
|
||||
--btn: #e60012;
|
||||
--btn-fg: #ffffff;
|
||||
--well: #050505;
|
||||
--well-pad: 0.75rem;
|
||||
--phosphor: #ff1a2e;
|
||||
--live-edge: transparent;
|
||||
--glow: 0 0 12px color-mix(in srgb, var(--signal) 55%, transparent);
|
||||
--glow-soft: 0 0 8px color-mix(in srgb, var(--signal) 40%, transparent);
|
||||
--scan: repeating-linear-gradient(
|
||||
0deg,
|
||||
rgb(255 255 255 / 0.03) 0 1px,
|
||||
transparent 1px 3px
|
||||
);
|
||||
}
|
||||
|
||||
:root[data-theme="light"] {
|
||||
--ground: #f4f4f4;
|
||||
--panel: #ebebeb;
|
||||
--ink: #0a0a0a;
|
||||
--ink-muted: #444444;
|
||||
--ink-faint: #666666;
|
||||
--rule: #cccccc;
|
||||
--strong: #111111;
|
||||
--signal: #c40018;
|
||||
--quote: #9a6b00;
|
||||
--btn: #c40018;
|
||||
--btn-fg: #ffffff;
|
||||
--well: #f4f4f4;
|
||||
--well-pad: 0;
|
||||
--phosphor: #c40018;
|
||||
--glow: none;
|
||||
--glow-soft: none;
|
||||
--scan: none;
|
||||
--live-edge: var(--signal);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-ground: var(--ground);
|
||||
--color-panel: var(--panel);
|
||||
--color-ink: var(--ink);
|
||||
--color-ink-muted: var(--ink-muted);
|
||||
--color-ink-faint: var(--ink-faint);
|
||||
--color-rule: var(--rule);
|
||||
--color-strong: var(--strong);
|
||||
--color-signal: var(--signal);
|
||||
--color-quote: var(--quote);
|
||||
--color-btn: var(--btn);
|
||||
--color-btn-fg: var(--btn-fg);
|
||||
--color-well: var(--well);
|
||||
--color-phosphor: var(--phosphor);
|
||||
--font-display: "Chakra Petch", "Arial", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
@utility clip-notch {
|
||||
/* Filled CTAs only (bg-btn etc.). Clip alone - solid fill defines the edge.
|
||||
Outline badges must use .wire-badge instead (border + clip-path eats strokes). */
|
||||
clip-path: polygon(
|
||||
0 0,
|
||||
calc(100% - 0.5rem) 0,
|
||||
100% 0.5rem,
|
||||
100% 100%,
|
||||
0.5rem 100%,
|
||||
0 calc(100% - 0.5rem)
|
||||
);
|
||||
}
|
||||
|
||||
@utility clip-notch-sm {
|
||||
/* Filled small controls only. Outline badges: use .wire-badge. */
|
||||
clip-path: polygon(0 0, calc(100% - 5px) 0, 100% 5px, 100% 100%, 0 100%);
|
||||
}
|
||||
|
||||
/* The newest wire entry sits on the well and reads in phosphor - the visible
|
||||
proof that the record is live. Scanlines are part of the well surface and
|
||||
disappear with it in light. Unlayered so it wins over utilities. */
|
||||
#activity-wire {
|
||||
--wire-badge-fill: var(--ground);
|
||||
}
|
||||
|
||||
/* Every row reserves the edge so live and stale rows stay aligned; only the
|
||||
live row paints it. In dark --live-edge is transparent because the well slab
|
||||
and the glow already say "live"; in light they both flatten to nothing, so
|
||||
the red edge is the only surface cue there is. */
|
||||
#activity-wire article,
|
||||
#shoutbox-messages article {
|
||||
border-left: 2px solid transparent;
|
||||
}
|
||||
|
||||
#activity-wire article:first-of-type {
|
||||
background-color: var(--well);
|
||||
background-image: var(--scan);
|
||||
border-left-color: var(--live-edge);
|
||||
/* Hollow badge interiors must match the well, not the page ground. */
|
||||
--wire-badge-fill: var(--well);
|
||||
}
|
||||
|
||||
#activity-wire article:first-of-type :is(span, time, a) {
|
||||
color: var(--phosphor);
|
||||
text-shadow: var(--glow-soft);
|
||||
}
|
||||
|
||||
#activity-wire article:first-of-type .wire-badge {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
/* The newest shout gets the same live treatment as the wire's newest entry.
|
||||
The log reads chronologically, so the newest message is the LAST article.
|
||||
Only the provenance line (handle + time) glows - shout bodies are user
|
||||
prose, not telemetry, and stay in ink. */
|
||||
#shoutbox-messages article:last-of-type {
|
||||
background-color: var(--well);
|
||||
background-image: var(--scan);
|
||||
border-left-color: var(--live-edge);
|
||||
}
|
||||
|
||||
#shoutbox-messages article:last-of-type :is(time, a) {
|
||||
color: var(--phosphor);
|
||||
text-shadow: var(--glow-soft);
|
||||
}
|
||||
|
||||
/* Default hole colour for outline notched badges. Override on non-ground
|
||||
surfaces (e.g. #activity-wire article:first-of-type sets --well). */
|
||||
:root {
|
||||
--wire-badge-fill: var(--ground);
|
||||
}
|
||||
|
||||
.bg-panel {
|
||||
--wire-badge-fill: var(--panel);
|
||||
}
|
||||
|
||||
/* Notched badge with a continuous stroke (top + diagonal included).
|
||||
Never use border + clip-path for outlines - clip-path eats the stroke.
|
||||
Shell = currentColor; hole = --wire-badge-fill; label above. */
|
||||
.wire-badge {
|
||||
--wire-notch: 5px;
|
||||
--wire-stroke: 2px;
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border: none !important;
|
||||
background-color: currentColor;
|
||||
clip-path: polygon(
|
||||
0 0,
|
||||
calc(100% - var(--wire-notch)) 0,
|
||||
100% var(--wire-notch),
|
||||
100% 100%,
|
||||
0 100%
|
||||
);
|
||||
padding: var(--wire-stroke);
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
.wire-badge::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: var(--wire-stroke);
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
background: var(--wire-badge-fill, var(--ground));
|
||||
clip-path: polygon(
|
||||
0 0,
|
||||
calc(100% - max(0px, var(--wire-notch) - var(--wire-stroke))) 0,
|
||||
100% max(0px, var(--wire-notch) - var(--wire-stroke)),
|
||||
100% 100%,
|
||||
0 100%
|
||||
);
|
||||
}
|
||||
|
||||
.wire-badge-label {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: inline-block;
|
||||
padding-inline: 0.375rem;
|
||||
padding-block: 0.125rem;
|
||||
color: inherit;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
/* Solid filled notched badges: slab only, no hollow. */
|
||||
.wire-badge.bg-ink {
|
||||
background-color: var(--ink) !important;
|
||||
color: var(--ground);
|
||||
}
|
||||
|
||||
.wire-badge.bg-signal {
|
||||
background-color: var(--signal) !important;
|
||||
color: var(--ground);
|
||||
}
|
||||
|
||||
.wire-badge.bg-btn {
|
||||
background-color: var(--btn) !important;
|
||||
color: var(--btn-fg);
|
||||
}
|
||||
|
||||
.wire-badge.bg-ink::before,
|
||||
.wire-badge.bg-signal::before,
|
||||
.wire-badge.bg-btn::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wire-badge.bg-ink .wire-badge-label,
|
||||
.wire-badge.bg-signal .wire-badge-label {
|
||||
color: var(--ground);
|
||||
}
|
||||
|
||||
.wire-badge.bg-btn .wire-badge-label {
|
||||
color: var(--btn-fg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Theme toggle: the pressed appearance is derived from the same source of
|
||||
truth as the colours themselves - the `data-theme` attribute on <html> -
|
||||
rather than from `aria-pressed`, which JavaScript can only set after the
|
||||
page has already painted. The server has no idea which theme a visitor
|
||||
chose, so it renders every button unpressed; without this the toggle
|
||||
visibly snapped to the right option a moment after load.
|
||||
|
||||
Absent attribute means "follow the OS", which is the default, so that case
|
||||
needs no script at all. `aria-pressed` is still synced in JS because screen
|
||||
readers are unaffected by a paint-time flash. */
|
||||
:root:not([data-theme]) [data-theme-option="system"],
|
||||
:root[data-theme="light"] [data-theme-option="light"],
|
||||
:root[data-theme="dark"] [data-theme-option="dark"] {
|
||||
background-color: var(--panel);
|
||||
color: var(--ink);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue