/* The app's frame and the pieces every page shares: type, the sidebar, the bar atop each page, buttons, fields.
   After the site (www/static/css/site.css): one size of one weight, the black button and halftone mark.
   Clear supplies the app colors. */

/* GT America is declared in base.html, where its URL can carry the file's stamp. Geist Mono, for code, is declared
   only on a page with code to show (_macros.html's code_font), so no other page fetches it. */

/* Clear, and what each colour is for. One job a colour, so nothing means two things:
   - Blue (the accent) is yours: something to open, decide or act on. An unread dot, the Inbox, a link's focus, a
     selection, a switch that's on, and the line a chart is about.
   - Ink and greys are everything else: words and rules, and what's under way or set aside. In a ramp from ink to a
     pale grey, the further something is from needing you, the paler (Home's boxes after the Inbox; a source that's
     reading is ink, one that waits or is paused a ring).
   - Green, amber and red say a data source's health, an error, or that a button takes something away, and nothing
     else: never a series in a chart, never a box.
   - Orange is a chart's second line, and only that.
   Each set was checked with the dataviz skill's validator: blue and orange as a categorical pair (colour-blind
   separation and contrast), the grey ramp as an ordinal one (one hue, even steps, its pale end visible). */
:root {
  --color-background: #FAFBFC;
  --color-surface: #E9EDF2;
  --color-ink: #253040;
  --color-accent: #3478D4;
  --color-success: #26966C;
  --color-warning: #E3B344;
  --color-error: #D86464;
  --color-button: #000000;
  --color-button-hover: #333333;
  --color-on-button: #FFFFFF;
  --color-text-body: #434C5A;
  --color-text-secondary: #5F6773;
  --color-text-muted: #656C76;  /* 4.5:1 on the silver surface as well as the page */
  --color-text-faint: #6E747E;  /* 4.5:1: it's set small (keyboard hints) */
  --color-text-caption: #656D78;  /* 4.5:1 on the warm paper it's set on */
  --color-ink-soft: #949AA2;
  --color-border-strong: #A9AEB5;
  --color-placeholder: #9EA4AB;
  --color-text-disabled: #B6BAC0;
  --color-control-hover: #C0C4C9;
  --color-border-hover: #C7CACF;
  --color-rule-strong: #CBCED3;
  --color-control: #D2D4D8;
  --color-border: #D8DBDE;
  --color-border-soft: #DEE1E4;
  --color-divider: #ECF0F4;
  --color-field: #EEF1F5;
  --color-rail: #EFF2F6;
  --color-hover: #F3F5F8;
  --color-paper: #F7EDE7;
  --color-error-text: #A6555A;
  /* Marks on the page need 3:1 against it (WCAG 1.4.11), text 4.5:1: where a Clear color is too light for that,
     a deeper shade of it stands in. */
  --color-danger: #A6555A;  /* the danger button: white text on it, 5.2:1 */
  --color-danger-hover: #8F474C;
  --color-warning-mark: #B5861B;  /* a status dot in Clear yellow's hue: 3:1, on a row lit by the pointer too */
  --color-orange-mark: #DD772B;  /* a chart line in Clear orange's hue, 3:1 */
  --color-error-hover: #BD5C5F;
  --color-success-hover: #1F7D5A;  /* a synced sync in a source's sparkline, pointed at */
  --color-warning-text: #695F41;
  --color-accent-hover: #316BB9;
  --color-accent-text: #3064AB;
  --color-accent-border: #BFD4F0;
  --color-selection: rgba(52, 120, 212, .10);
  --color-warning-surface: rgba(227, 179, 68, .20);
  --color-unread: var(--color-accent);
  /* Home's boxes: the Inbox is yours; the rest, ink to pale, as far from needing you as they are. */
  --color-box-inbox: var(--color-accent);
  --color-box-in-progress: var(--color-ink);
  --color-box-snoozed: var(--color-text-secondary);
  --color-box-done: var(--color-ink-soft);
  --color-box-wont-do: var(--color-border-strong);
  --color-chart-primary: var(--color-accent);
  --color-chart-secondary: var(--color-orange-mark);
  --color-chart-context: var(--color-ink-soft);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { background: var(--color-background); }
body {
  background: var(--color-background);
  font: 400 15px/20px 'GT America', system-ui, sans-serif;
  font-synthesis: none;  /* one licensed weight: never fake a bold or an italic from it */
  font-variant-numeric: tabular-nums;  /* figures line up, in lists and tables alike */
  color: var(--color-ink);
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 { font: inherit; }
ul, ol { list-style: none; }
fieldset { border: 0; min-width: 0; }
button, input, textarea, select { font: inherit; color: inherit; }
.g { color: var(--color-text-secondary); }
/* Code, and only code: a scope, a key, a secret being pasted in. Everything around it (its label, its help, a saved
   secret's hint) stays in GT America. Its x-height is set to GT America's (half its size), so it sits level with
   the text around it, in Geist Mono or in the face standing in for it while it loads. */
code, .code { font-family: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size-adjust: 0.5; }
/* For a screen reader alone. */
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
:is(input, textarea):not([type="checkbox"]):focus-visible { outline: none; }
.segmented input:focus-visible, .ticks input:focus-visible { outline: none; }

/* ───────── the frame: the sidebar, and the page beside it ───────── */
.shell { display: grid; grid-template-columns: 208px minmax(0, 1fr); min-height: 100vh; min-height: 100svh; }
.sidebar { position: sticky; top: 0; display: flex; flex-direction: column; height: 100vh; height: 100svh; padding: 0 12px; background: var(--color-surface); border-right: 1px solid var(--color-surface); }
.brand { display: flex; align-items: center; width: max-content; height: 56px; padding: 0 8px; }
.brand svg { width: 18px; height: 18px; flex: none; }
.menu { display: flex; flex-direction: column; gap: 2px; margin-top: 8px; }
.menu a { display: flex; justify-content: space-between; align-items: center; padding: 6px 8px; border-radius: 6px; color: var(--color-text-secondary); transition: color .15s ease-in, background .15s ease-in; }
.menu a:hover { color: var(--color-ink); }
.menu a[aria-current="page"] { color: var(--color-accent-text); background: var(--color-selection); }
.count { color: var(--color-text-muted); margin-left: 8px; }
/* A button in the menu (Sign out) reads as its links do. */
.menu button { width: 100%; padding: 6px 8px; border: 0; border-radius: 6px; background: none; color: var(--color-text-secondary); text-align: left; cursor: pointer; transition: color .15s ease-in; }
.menu button:hover { color: var(--color-ink); }
/* At the sidebar's foot, the workspace: its name, then its members, and a way out. */
.account { margin-top: auto; padding: 16px 0 12px; }
.workspace-name { padding: 0 8px 4px; color: var(--color-text-muted); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.main { min-width: 0; }

/* The bar atop every page: its title, and what can be done there. */
.bar { display: flex; align-items: center; gap: 24px; height: 56px; padding: 0 32px; border-bottom: 1px solid var(--color-surface); background: var(--color-background); }
/* Its button ends where the page's content does (1080px wide at most), not at the window's edge. */
.bar .button { margin-right: max(0px, calc(100% - 1080px)); }
.bar h1 { flex: none; }
.bar .button { margin-left: auto; }
.crumbs { display: flex; align-items: center; gap: 8px; }
.crumbs a { color: var(--color-text-secondary); transition: color .15s ease-in; }
.crumbs a:hover { color: var(--color-ink); }
.content { padding: 32px 32px 128px; }

/* ───────── buttons and links ───────── */
/* As on the site: black, a little rounded. */
.button { display: inline-block; border: 0; cursor: pointer; background: var(--color-button); color: var(--color-on-button); border-radius: 6px; padding: 6px 11px; transition: background .15s ease-in; white-space: nowrap; }
.button:hover { background: var(--color-button-hover); }
.button.danger { background: var(--color-danger); color: var(--color-on-button); }
.button.danger:hover { background: var(--color-danger-hover); }
/* Its quiet sibling, for the many buttons on a page that aren't its main one. */
.quiet { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--color-border-soft); background: var(--color-background); border-radius: 6px; padding: 5px 10px; cursor: pointer; white-space: nowrap; transition: border-color .15s ease-in, background .15s ease-in; }
.quiet:hover { border-color: var(--color-border-hover); background: var(--color-hover); }
/* A quiet button that takes something away (a focus area; a member, an invitation, an API key): in the danger red's
   text colour, as the trigger of a source's Remove is, its edge turning red when pointed at. */
.quiet.danger, .quiet.danger:hover { color: var(--color-error-text); }
.quiet.danger:hover { border-color: var(--color-error-text); }
/* Links in running text: a hairline under them, darkening on hover. A button can be one, too. */
.link { border-bottom: 1px solid var(--color-rule-strong); transition: border-color .15s ease-in; cursor: pointer; }
button.link { border-width: 0 0 1px; background: none; padding: 0; }
.link:hover { border-color: var(--color-ink); }
/* The key a button answers to: faint, and only where there is a keyboard. */
kbd { font: inherit; font-size: 12px; line-height: 16px; color: var(--color-text-faint); }
@media (hover: none) { kbd { display: none; } }

/* ───────── fields ───────── */
/* A field is a soft well, a shade off the page. Pointed at, it deepens; given the focus, it becomes a white sheet with
   a blue edge from the app's accent. The edge is the focus ring, so it needs no other. */
input[type="text"], input[type="url"], input[type="email"], input[type="password"], input:not([type]), textarea, .affix {
  background: var(--color-field); border: 1px solid transparent; border-radius: 6px;
  transition: background .15s ease-in, border-color .15s ease-in;
}
input[type="text"], input[type="url"], input[type="email"], input[type="password"], input:not([type]), textarea {
  display: block; width: 100%; padding: 6px 10px; line-height: 20px; outline: none; appearance: none;
}
:is(input[type="text"], input[type="url"], input[type="email"], input[type="password"], input:not([type]), textarea):hover, .affix:hover { background: var(--color-surface); }
:is(input[type="text"], input[type="url"], input[type="email"], input[type="password"], input:not([type]), textarea):focus, .affix:focus-within { background: var(--color-background); border-color: var(--color-accent); }
.invalid :is(input, textarea, .affix) { background: var(--color-background); border-color: var(--color-error); }
input::placeholder, textarea::placeholder { color: var(--color-placeholder); opacity: 1; }
/* Text areas grow with what's typed, where the browser can; long pastes (a key) scroll. */
textarea { resize: none; min-height: calc(3lh + 14px); max-height: calc(12lh + 14px); field-sizing: content; }
/* Code pasted in (a JSON key, a PEM key) keeps its lines as they are: never wrapped, and one wider than the field
   scrolls sideways. The template's wrap="off" says the same, for an engine that reads that and not this. */
textarea.code { white-space: pre; overflow-wrap: normal; overflow-x: auto; }

/* A field with its unit inside it: "80 requests a minute". */
.affix { display: inline-flex; align-items: center; max-width: 100%; }
.affix { cursor: text; }
.affix input, .affix input:hover, .affix input:focus { background: none; border-color: transparent; width: 4em; flex: none; padding-right: 6px; }
/* The enclosing field owns the error border, including while its input is hovered or focused. */
.invalid .affix input { background: none; border-color: transparent; }
.affix > span { padding-right: 10px; color: var(--color-text-muted); white-space: nowrap; }
/* Where the browser can, the field is as wide as its number, so the unit follows it closely. */
@supports (field-sizing: content) {
  .affix input { width: auto; min-width: calc(2ch + 16px); field-sizing: content; }
}

/* Something to write: a grey line saying what, and the field under it. Every form ends the same way, with its
   button under its fields, on the left; nothing is sent from inside a field. */
.write { display: block; }
.write > textarea { margin-top: 8px; }
form > .button { margin-top: 12px; }

/* A checkbox is a switch: off, a grey track; on, blue, its pale knob slid across. */
input[type="checkbox"] {
  appearance: none; position: relative; flex: none; width: 28px; height: 16px; margin: 0; border-radius: 8px;
  background: var(--color-control); cursor: pointer; transition: background .15s ease-in;
}
input[type="checkbox"]::before {
  content: ''; position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: var(--color-background);
  transition: transform .2s cubic-bezier(.2, .7, .1, 1);
}
input[type="checkbox"]:hover { background: var(--color-control-hover); }
input[type="checkbox"]:checked { background: var(--color-accent); }
input[type="checkbox"]:checked:hover { background: var(--color-accent-hover); }
input[type="checkbox"]:checked::before { transform: translateX(12px); }
/* A switch with its words beside it, the whole line pressable. */
.toggle { display: flex; justify-content: space-between; align-items: flex-start; gap: 24px; cursor: pointer; }
.toggle > input { margin-top: 2px; }
.toggle-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

/* A few short choices, side by side: the chosen one a white sheet on a grey track. The radios stay, unseen,
   for the keyboard and for screen readers. */
.segmented { display: inline-flex; flex-wrap: wrap; gap: 2px; padding: 2px; border-radius: 6px; background: var(--color-surface); max-width: 100%; }
.segmented label { position: relative; display: block; }
.segmented input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.segmented span { display: block; padding: 3px 12px; border: 1px solid transparent; border-radius: 4px; color: var(--color-text-secondary); white-space: nowrap; transition: color .15s ease-in, background .15s ease-in; }
.segmented label:hover span { color: var(--color-ink); }
.segmented input:checked + span { background: var(--color-background); border-color: var(--color-accent-border); color: var(--color-accent-text); }
.segmented input:focus-visible + span { outline: 2px solid var(--color-accent); outline-offset: 1px; }

/* Longer choices, one a line, as the site's survey sets them: picked, one is marked with the asterisk, turning
   into place, and the rest fall back. */
.ticks { display: flex; flex-direction: column; }
.ticks label { position: relative; display: block; padding: 3px 0 3px 18px; color: var(--color-text-secondary); cursor: pointer; transition: color .15s ease-in; }
.ticks label:hover { color: var(--color-ink); }
.ticks input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.ticks .tick { position: absolute; left: 2px; top: 8px; opacity: 0; }
.ticks input:checked ~ .tick { opacity: 1; }
.ticks label:has(input:checked) { color: var(--color-ink); }
.ticks:has(input:checked) label:not(:has(input:checked)) { color: var(--color-text-disabled); }
.ticks:has(input:checked) label:not(:has(input:checked)):hover { color: var(--color-text-secondary); }
.ticks input:focus-visible ~ span { text-decoration: underline; text-underline-offset: 3px; }

.field > label:not(.affix) { display: block; margin-bottom: 6px; }
.error { color: var(--color-error-text); margin-top: 6px; }
.help { color: var(--color-text-secondary); margin-top: 6px; }

/* How a data source stands, by a dot. Its health in green, amber and red: synced, setup to finish, something to
   fix. Otherwise ink and grey: reading (ink), waiting for its first read (an ink ring), paused (a grey ring), and
   faint where Asterisk doesn't read it yet, or its state can't be known just now. On Data sources, and on Home. */
.state { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
.state::before { content: ''; width: 8px; height: 8px; border-radius: 50%; flex: none; }
.state.synced::before { background: var(--color-success); }
.state.setup::before { background: var(--color-warning-mark); }
.state.attention::before { background: var(--color-error); }
.state.syncing::before { background: var(--color-ink); }
.state.ready::before, .state.waiting::before { box-shadow: inset 0 0 0 1.5px var(--color-ink); }
.state.paused::before { box-shadow: inset 0 0 0 1.5px var(--color-border-strong); }
.state.unavailable { color: var(--color-text-muted); }
.state.unavailable::before, .state.unknown::before { background: var(--color-control); }

/* ───────── a readout ───────── */
/* The card a mark in a chart reads out in, beside it, as it's pointed at: what it is, then the rest, in grey. Home's
   dots and days (home.js), and the syncs in a source's sparkline (sources.js). */
.tip { position: absolute; z-index: 6; max-width: 22em; padding: 8px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-background); font-size: 13px; line-height: 18px; pointer-events: none; }
.tip[hidden] { display: none; }
.tip b { display: block; font-weight: inherit; color: var(--color-ink); text-wrap: balance; }
.tip > span { display: block; color: var(--color-text-secondary); }
.tip b + span { margin-top: 2px; }

/* ───────── what's said once a change is made ───────── */
/* The notice: what was just done, at the foot of the page, level with its text, in Clear slate. */
.notice {
  position: fixed; left: calc(208px + 32px); bottom: 24px; z-index: 10; display: flex; align-items: center; gap: 12px;
  max-width: min(640px, calc(100vw - 208px - 64px)); padding: 8px 16px; border-radius: 6px; background: var(--color-ink); color: var(--color-background);
  animation: rise .3s cubic-bezier(.16, 1, .3, 1); transition: opacity .3s ease-in;
}
.notice:has(form) { padding-right: 8px; }
.notice.gone { opacity: 0; pointer-events: none; }
.notice p { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.notice .g { color: rgba(255, 255, 255, .62); margin-left: 4px; }
.notice kbd { color: rgba(255, 255, 255, .5); }
.undo { display: inline-flex; align-items: center; gap: 6px; background: none; border: 0; color: var(--color-background); padding: 4px 8px; border-radius: 4px; cursor: pointer; transition: background .15s ease-in; }
.undo:hover { background: rgba(255, 255, 255, .12); }
@keyframes rise { from { opacity: 0; transform: translateY(8px); } }
/* A form that couldn't be saved says so where it is, above it: that's not a notice, it's the form's. */
.flash { margin-bottom: 24px; }
.flash.alert { color: var(--color-error-text); }
/* The mark as a tick, turning into place, as when an answer is picked on the site. */
.tick { width: 10px; height: 10px; flex: none; }
.flash .tick, .notice .tick, .ticks input:checked ~ .tick { animation: tick .7s cubic-bezier(.2, .7, .1, 1); }
@keyframes tick { from { transform: rotate(-180deg) scale(.3); opacity: 0; } to { transform: none; opacity: 1; } }

/* An empty list: the mark, faint, and a line or two on what would be here. It has no padding of its own: every
   page sets it where its content starts (32px under the bar, 32px in from the sidebar, less on phones), so moving
   between empty pages, the mark and the first line stay put. */
.empty { max-width: 26em; }
.empty p + p { margin-top: 4px; }
.empty-mark { display: block; width: 32px; height: 32px; color: var(--color-control); margin-bottom: 16px; }
.empty .button { margin-top: 24px; }
/* A page that starts empty and offers what to fill it with: the mark, a line, a shorter one, then the offer. */
.start { max-width: 34em; margin-bottom: 32px; }
.start p + p { margin-top: 4px; }
.lede { max-width: 34em; margin-bottom: 32px; }

/* ───────── outside a workspace: signing in, making one ───────── */
/* The page alone, no sidebar: a narrow column a little above the middle, the mark atop it in black, as the
   sidebar sets it; a line saying where you are, a grey one, then the form, its button under its fields. */
.outside { display: flex; justify-content: center; min-height: 100vh; min-height: 100svh; padding: 0 16px; }
.door { width: 100%; max-width: 22em; padding: max(64px, 20vh) 0 64px; }
.door-mark { display: block; width: 24px; height: 24px; margin-bottom: 32px; }
.door h1 + .g { margin-top: 4px; }
.door > .g + :is(form, .button, .local) { margin-top: 32px; }
.door .button { display: inline-block; }
.door-foot { margin-top: 32px; }
.door-foot .g { margin-right: 4px; }
.local { padding: 16px; border-radius: 6px; background: var(--color-surface); }
.local .button { margin-top: 12px; }

/* A form of a few fields, one under another, its button under them, on the left. */
.stack { display: flex; flex-direction: column; gap: 20px; max-width: 26em; padding: 8px 10px; }
.stack .button { margin-top: 0; align-self: flex-start; }

/* ───────── choosing from a list ───────── */
/* In sections under a hairline, the kind of thing on the left, the things in a grid on the right, each a name and
   a line on what it is, lit when pointed at. Links (the catalog of data sources) or buttons (suggested focus
   areas), set alike. */
.category { display: grid; grid-template-columns: 10em minmax(0, 1fr); gap: 24px; max-width: 1080px; padding: 16px 0; border-top: 1px solid var(--color-surface); }
.category h2 { padding-top: 8px; }
.catalog { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 2px 16px; }
.catalog :is(a, button) { display: block; width: 100%; padding: 8px 10px; border: 0; border-radius: 6px; background: none; text-align: left; cursor: pointer; transition: background .15s ease-in; }
.catalog :is(a, button):hover { background: var(--color-surface); }
.catalog button { display: flex; flex-direction: column; justify-content: flex-start; }  /* a button centres what's in it; set it at the top, as a link's is */
.catalog .name, .catalog .g { display: block; }
/* What Asterisk doesn't read from yet: there, but faint, and nothing to click. */
.catalog .soon { padding: 8px 10px; color: var(--color-placeholder); cursor: default; }
.catalog .soon .g { color: var(--color-text-disabled); }
.soon-tag { margin-left: 8px; padding: 1px 6px; border-radius: 4px; font-size: 13px; color: var(--color-text-muted); background: var(--color-surface); }
.catalog .g { margin-top: 2px; }

/* ───────── narrower screens: the sidebar becomes a bar along the top ───────── */
@media (max-width: 1023px) {
  .category { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  .category h2 { padding: 0 10px; }
}
@media (max-width: 899px) {
  .shell { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr; }
  /* One line along the top; where it's longer than the screen, it scrolls sideways, as the mailbox's tabs do. */
  .sidebar { position: static; height: auto; flex-direction: row; align-items: center; gap: 16px; padding: 0 16px; border-right: 0; border-bottom: 1px solid var(--color-surface); overflow-x: auto; scrollbar-width: none; }
  .sidebar::-webkit-scrollbar { display: none; }
  .brand, .menu { flex: none; }
  .menu :is(a, button) { white-space: nowrap; }
  .brand { height: 48px; padding: 0; }
  .menu { flex-direction: row; margin: 0; }
  .account { flex: none; margin: 0 0 0 auto; padding: 0; }
  .workspace-name { display: none; }
  .bar { padding: 0 16px; height: 48px; }
  .content { padding: 24px 16px 96px; }
  .notice { left: 16px; right: 16px; bottom: 16px; max-width: none; }
}
/* Phones: 16px type, or iOS zooms into a field when it's tapped. */
@media (max-width: 767px) {
  input, textarea { font-size: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .flash .tick, .notice .tick, .ticks input:checked ~ .tick { animation: none; }
  .notice { animation: none; }
  input[type="checkbox"]::before { transition: none; }
}
