Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

166 linesCodeBlameRaw
1@import "tailwindcss" source(".");
2@import "@g1t/theme/tokens.css";
3@import "@g1t/theme/fonts.css";
4
5/* Tailwind's names for the shared g1t tokens, as in apps/web. */
6@theme {
7 --font-sans: var(--g1t-font-sans);
8 --font-display: var(--g1t-font-display);
9 --font-mono: var(--g1t-font-mono);
10
11 --color-bg: var(--g1t-bg);
12 --color-surface: var(--g1t-surface);
13 --color-raised: var(--g1t-raised);
14 --color-line: var(--g1t-line);
15 --color-line-strong: var(--g1t-line-strong);
16
17 --color-fg: var(--g1t-fg);
18 --color-fg-soft: var(--g1t-fg-soft);
19 --color-muted: var(--g1t-muted);
20 --color-faint: var(--g1t-faint);
21
22 --color-accent: var(--g1t-accent);
23 --color-accent-hover: var(--g1t-accent-hover);
24 --color-accent-dim: var(--g1t-accent-dim);
25
26 --color-success: var(--g1t-success);
27 --color-success-dim: var(--g1t-success-dim);
28
29 --color-info: var(--g1t-info);
30 --color-merged: var(--g1t-merged);
31 --color-warn: var(--g1t-warn);
32 --color-danger: var(--g1t-danger);
33}
34
35html {
36 color-scheme: dark;
37}
38
39body {
40 @apply bg-bg font-sans text-fg antialiased;
41}
42
43::selection {
44 background: color-mix(in srgb, var(--color-accent) 35%, transparent);
45}
46
47@layer base {
48 :focus-visible {
49 outline: 2px solid var(--color-accent);
50 outline-offset: 2px;
51 }
52
53 .grid > * {
54 min-width: 0;
55 }
56
57 /* Page titles in the headline face, as on g1t.sh. */
58 :where(h1) {
59 font-family: var(--font-display);
60 font-optical-sizing: auto;
61 }
62
63 :root {
64 accent-color: var(--color-accent);
65 }
66
67 /* Figures line up in columns of money. */
68 .tabular {
69 font-variant-numeric: tabular-nums;
70 }
71}
72
73/*
74 * A long-running button says it is running with CSS alone, before any
75 * script has loaded: a clicked button keeps focus while the old page waits
76 * for the response (components/progress.tsx lets go of it once a <Form>'s
77 * answer is in). `:focus-visible` is left out, so tabbing to it does not
78 * read as running.
79 */
80.run-button .run-busy,
81.run-button + .run-note {
82 display: none;
83}
84.run-button:focus:not(:focus-visible) .run-idle {
85 display: none;
86}
87.run-button:focus:not(:focus-visible) .run-busy {
88 display: inline-flex;
89 align-items: center;
90 gap: 0.5rem;
91}
92.run-button:focus:not(:focus-visible) + .run-note {
93 display: inline;
94}
95.run-spinner {
96 width: 0.8rem;
97 height: 0.8rem;
98 border-radius: 9999px;
99 border: 2px solid currentColor;
100 border-right-color: transparent;
101 animation: run-spin 0.8s linear infinite;
102}
103@keyframes run-spin {
104 to {
105 transform: rotate(360deg);
106 }
107}
108@media (prefers-reduced-motion: reduce) {
109 .run-spinner {
110 animation: none;
111 }
112}
113
114/*
115 * Every other submit button says it is working the same way: a clicked
116 * button keeps focus while the page waits for the answer, so it dims
117 * and shows a spinner. The page that comes back is
118 * fresh (every action redirects), and says what happened. Nothing may
119 * stop pointer events here: focus comes on mouse-down, before the click.
120 */
121form button[type="submit"]:not(.run-button):focus:not(:focus-visible) {
122 opacity: 0.75;
123}
124form button[type="submit"]:not(.run-button):focus:not(:focus-visible)::before {
125 content: "";
126 flex: none;
127 width: 0.8rem;
128 height: 0.8rem;
129 border-radius: 9999px;
130 border: 2px solid currentColor;
131 border-right-color: transparent;
132 animation: run-spin 0.8s linear infinite;
133}
134form button[type="submit"]:not(.run-button):focus:not(:focus-visible) > svg {
135 display: none;
136}
137@media (prefers-reduced-motion: reduce) {
138 form button[type="submit"]:focus:not(:focus-visible)::before {
139 animation: none;
140 }
141}
142
143/*
144 * The credit and terms forms (components/billing.tsx) show a field only for the
145 * choice it belongs to, with CSS alone: the custom amount and the slug for
146 * Custom, a refund's details for Refund, the expiry for anything else, and
147 * the date for "On a date". Where `:has()` is not supported (or without
148 * CSS) every field shows, and the server ignores the ones that do not apply.
149 */
150@supports selector(:has(*)) {
151 .credit-form .when-custom,
152 .credit-form .when-refund,
153 .credit-form .when-date,
154 .terms-form .when-custom {
155 display: none;
156 }
157 .credit-form:has(input[name="preset"][value="custom"]:checked) .when-custom,
158 .terms-form:has(input[name="preset"][value="custom"]:checked) .when-custom,
159 .credit-form:has(input[name="kind"][value="refund"]:checked) .when-refund,
160 .credit-form:has(input[name="expires"][value="date"]:checked) .when-date {
161 display: block;
162 }
163 .credit-form:has(input[name="kind"][value="refund"]:checked) .when-not-refund {
164 display: none;
165 }
166}