Something went wrong. Try again.
Cooperative email for PDS operators
Something went wrong. Try again.
18 kB · 628 lines
CSS
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629:root { /* Canonical comail brand palette — locked by Scott 2026-05-17. Mirror of web-frontend/src/assets/brand-colors.json and the Astro chrome at web-frontend/src/styles/globals.css. Do not introduce new colors without checking. */ --brand-light-blue: #3fa1c0; /* cammie body */ --brand-dark-blue: #02413c; /* cammie outline teal */ --brand-darkest-blue: #012102; /* primary ink */ --brand-yellow: #e1c240; /* cammie beak / highlight */ --brand-background: #dfe0c0; /* sage paper */
/* Semantic tokens derive from brand. The earlier oklch warm-paper palette is retired; we now ride sage paper as the canonical bg in parity with the Astro chrome. */ --bg: var(--brand-background); --ink: var(--brand-darkest-blue); --muted: #5b6660; /* mid-tone tuned for sage bg */ --line: #b9bd9a; /* hairline tuned for sage bg */
--accent: var(--brand-light-blue); --accent-ink: var(--brand-dark-blue); --surface: #f5f5e0; /* off-white surface for credential boxes */
/* Legacy aliases preserved — call-sites continue to resolve. */ --brand-blue: var(--brand-light-blue); --brand-blue-deep: var(--brand-dark-blue);
--font-display: 'Young Serif', 'Iowan Old Style', 'Palatino Linotype', Palatino, serif; --font-body: 'Atkinson Hyperlegible', 'Charter', 'Georgia', serif;
/* Type scale: 1.25 ratio, fixed rem (product UI, not marketing). Masthead is tuned to fit above the fold on a 720-line laptop without sacrificing the newspaper grammar. */ --t-xs: 0.8125rem; /* 13px */ --t-s: 0.9375rem; /* 15px */ --t-m: 1.0625rem; /* 17px */ --t-l: 1.1875rem; /* 19px */ --t-xl: 1.375rem; /* 22px */ --t-2xl: 2rem; /* 32px */ --t-3xl: 3rem; /* 48px — masthead */}* { box-sizing: border-box; }html, body { margin: 0; padding: 0; background: var(--bg); color: var(--ink); font-family: var(--font-body); font-size: var(--t-m); line-height: 1.45; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;}/* Body is a flex column so the footer can stick to the viewport bottom on short pages (see `footer { margin-top: auto; }` below). Without this, the footer floats mid-page when the content column is shorter than the viewport. */html { min-height: 100%; }body { min-height: 100vh; display: flex; flex-direction: column; }/* Body links are ink with a cammie cyan-blue accent underline. The accent stays heroic by living on the drop-cap, primary button, and credential callout — not stippled across every paragraph. */a { color: var(--ink); text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 1.5px; text-underline-offset: 3px;}a:hover { color: var(--accent-ink); text-decoration-color: var(--accent-ink);}code { font-family: 'JetBrains Mono', 'Menlo', 'Consolas', monospace; font-size: 0.95em; /* Pure white fill against warm paper — same treatment as <pre> and credential boxes. Reads as "data chit on stationery" rather than a bordered same-color region that blurs into prose. */ background: var(--surface); padding: 0 0.25em; border: 1px solid var(--line); border-radius: 2px;}pre { font-family: 'JetBrains Mono', 'Menlo', 'Consolas', monospace; font-size: 0.9em; background: var(--surface); color: var(--ink); border: 1px solid var(--line); padding: 1rem 1.25rem; border-radius: 2px; overflow-x: auto; white-space: pre-wrap; word-break: break-all; line-height: 1.5;}pre code { background: none; border: none; padding: 0; }
/* Top-of-page nav — subtle home link so every page can return to the marketing landing with one click. Lives above the masthead; typography-sized so it doesn't visually compete with the section mastheads below. */.topnav { font-family: var(--font-body); font-size: var(--t-xs); text-transform: uppercase; letter-spacing: 0.12em; color: var(--muted); margin-bottom: 1.5rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--line);}.topnav-home { color: var(--muted); text-decoration: none; font-weight: 700;}.topnav-home:hover { color: var(--accent);}
/* Persistent header navbar (internal ref). Rendered on every authenticated page (Account / Domains / Deliverability / Sign out) plus a right-aligned user chip. Replaces the ad-hoc "← Back to X" breadcrumbs that used to live in each authenticated sub-page. Logged-out pages pass NavState{} and render no navbar. */.appnav { display: flex; align-items: center; gap: 1.25rem; flex-wrap: wrap; margin: 0; padding: 0.75rem 2.5rem 0.65rem; border-bottom: 1px solid var(--line); font-family: var(--font-body); font-size: var(--t-s);}.appnav-list { display: flex; flex-wrap: wrap; gap: 1.1rem; margin: 0; padding: 0; list-style: none; align-items: baseline;}.appnav-list a { color: var(--ink); text-decoration: none; padding-bottom: 2px; border-bottom: 2px solid transparent; font-weight: 400; transition: color 120ms ease, border-color 120ms ease;}.appnav-list a:hover { color: var(--accent-ink); border-bottom-color: var(--accent-ink);}/* Active item — bold text + a 2px accent underline. The contract is the aria-current attribute; the visual is styled off it so screen readers and sighted users see the same affordance. */.appnav-list a[aria-current="page"] { font-weight: 700; border-bottom-color: var(--accent); color: var(--ink);}/* User chip — right-aligned handle/DID with a hairline left-border to read as "session metadata" rather than another nav item. margin-left:auto pushes it to the far right of the flex row. */.appnav-user { margin-left: auto; padding-left: 1rem; border-left: 1px solid var(--line); color: var(--muted); font-size: var(--t-xs); font-family: 'JetBrains Mono', 'Menlo', 'Consolas', monospace; word-break: break-all; max-width: 22rem;}/* Mobile (<480px) — nav items stay on one line; the user chip is hidden to keep the header a single clean row. */@media (max-width: 480px) { .appnav, .brand-strip { gap: 0.5rem; padding-left: 1.5rem; padding-right: 1.5rem; } .appnav-list { gap: 0.75rem 1rem; } .appnav-user { display: none; }}
.page { max-width: 680px; width: 100%; margin: 0 auto; padding: 2rem 2rem 2.5rem; flex: 1 0 auto;}
/* Masthead — deliberately large, newspaper-style. The leading 'A' of "Atmosphere" gets the accent color; the rest is ink. */.masthead { font-family: var(--font-display); font-size: var(--t-3xl); line-height: 1; letter-spacing: -0.03em; margin: 0 0 0.5rem; color: var(--ink);}.masthead .drop { color: var(--accent);}/* Sub-page masthead — smaller, no drop-cap. The drop-cap is reserved for the landing's brand mark; pages like /terms /privacy /aup /about are reference docs that cede visual authority to the landing. */.masthead-sub { font-size: var(--t-2xl); margin-bottom: 0.25rem;}/* Effective-date marginalia — the typographic convention for legal documents. Sits directly under the title in small-caps, before the lede. Replaces the awkward "Effective X. Lorem ipsum..." sentence-opener pattern used in the first draft. */.effective { font-family: var(--font-body); font-size: var(--t-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; color: var(--muted); margin: 0 0 1.25rem;}.lede { font-family: var(--font-body); font-style: italic; font-size: var(--t-l); color: var(--muted); line-height: 1.4; margin: 0 0 1rem; max-width: 32em;}
/* Section heading — Young Serif, smaller than masthead, with a hairline rule above. Evokes a typeset page break. */.section { margin-top: 1.75rem; padding-top: 1rem; border-top: 1px solid var(--line);}.section h2 { font-family: var(--font-display); font-size: var(--t-xl); font-weight: 400; letter-spacing: -0.01em; margin: 0 0 0.35rem;}.section p { margin: 0.35rem 0 0.6rem;}.section-lede { font-size: var(--t-s); color: var(--muted); margin: 0 0 1rem; max-width: 36em;}
/* Step number — small-caps marginalia, NOT a boxed card number. */.step-marker { display: block; font-family: var(--font-body); font-size: var(--t-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; color: var(--muted); margin-bottom: 0.25rem;}
/* Form — boxed fields on white surface. Earlier iterations used hairline-underline inputs (no box, just a bottom border), but those collided visually with the section dividers and readers couldn't tell what was input vs. structure. A subtle surface fill + 1px frame makes "this is a typeable field" unambiguous without dragging the page toward a generic webform aesthetic. */label { display: block; font-size: var(--t-s); font-weight: 700; margin-top: 1rem; margin-bottom: 0.25rem;}label + small { display: block; color: var(--muted); font-size: var(--t-xs); margin-bottom: 0.5rem;}input[type=text],input[type=email],textarea { display: block; width: 100%; font-family: inherit; font-size: var(--t-m); color: var(--ink); background: var(--surface); border: 1px solid var(--line); border-radius: 2px; padding: 0.6rem 0.75rem; margin-bottom: 0.5rem; outline: none; transition: border-color 120ms ease, box-shadow 120ms ease;}input[type=text]:focus,input[type=email]:focus,textarea:focus { border-color: var(--ink); box-shadow: inset 0 -2px 0 0 var(--accent);}.handle-input-wrapper { position: relative;}.handle-input-wrapper input[type=text] { padding-left: 1.75rem;}.handle-input-wrapper::before { content: "@"; position: absolute; left: 0.75rem; top: 0.6rem; font-family: 'JetBrains Mono', 'Menlo', monospace; font-size: var(--t-m); color: var(--muted); pointer-events: none; z-index: 1;}.handle-suggestions { position: absolute; left: 0; right: 0; bottom: 100%; background: var(--ink); color: var(--bg); border-radius: 2px 2px 0 0; z-index: 10; max-height: 260px; overflow-y: auto; box-shadow: 0 -4px 16px rgba(0,0,0,0.15);}.handle-suggestion { display: flex; align-items: center; gap: 0.6rem; padding: 0.5rem 0.75rem; cursor: pointer; transition: background 0.1s;}.handle-suggestion:hover,.handle-suggestion.active { background: oklch(0.30 0.02 70);}.suggestion-avatar { width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0; object-fit: cover;}.suggestion-avatar-placeholder { width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0; background: oklch(0.40 0.01 70);}.suggestion-text { display: flex; flex-direction: column; min-width: 0;}.suggestion-name { font-weight: 700; font-size: var(--t-s); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}.suggestion-handle { font-size: var(--t-xs); color: oklch(0.65 0.01 70); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}textarea { resize: vertical; line-height: 1.4; font-family: 'JetBrains Mono', 'Menlo', monospace; font-size: var(--t-s);}/* Buttons and button-styled links share one base. .btn-secondary is the ghost variant — muted, reserved for withdrawal actions (sign out) and secondary CTAs (sign in next to "Enroll a domain"). Keeping them as class variants on a single base means the aesthetic stays consistent when we change padding or weight in one place. */button,.btn { display: inline-block; font-family: inherit; font-size: var(--t-s); font-weight: 700; letter-spacing: 0.02em; color: var(--bg); background: var(--ink); border: 1px solid var(--ink); padding: 0.65rem 1.5rem; margin-top: 1.25rem; cursor: pointer; text-decoration: none; transition: background 120ms ease, color 120ms ease, border-color 120ms ease;}.btn-secondary,button.btn-secondary { color: var(--ink); background: transparent; border-color: var(--line);}button:hover,.btn:hover { background: var(--accent); border-color: var(--accent); color: var(--bg);}.btn-secondary:hover,button.btn-secondary:hover { background: var(--ink); border-color: var(--ink); color: var(--bg);}
/* Credential box — inverse of the page (surface white on paper). This is the ONE boxed element on the success page; everything else is just typography. Makes the API key impossible to miss. */.credential { margin: 1.5rem 0; padding: 1.25rem 1.5rem; background: var(--surface); border: 1px solid var(--line);}.credential-label { font-size: var(--t-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; color: var(--accent); margin-bottom: 0.5rem;}.credential-note { font-size: var(--t-xs); font-style: italic; color: var(--muted); margin-top: 0.75rem;}
.dns-block { margin: 1.25rem 0;}.dns-block-label { font-family: 'JetBrains Mono', monospace; font-size: var(--t-xs); color: var(--muted); margin-bottom: 0.25rem;}
.bullets { margin: 0.5rem 0; padding-left: 1.25rem;}.bullets li { margin-bottom: 0.25rem;}
/* Footer — light, one line, hairline rule. `margin-top: auto` on a flex child in a column container pushes the footer to the bottom of whatever space is left, so it sticks to the viewport bottom on short pages. The 2.25rem minimum keeps a comfortable gap from tall content pages (Terms, Privacy) because `auto` collapses to 0 when the flex parent is already at or beyond its main size. */footer { margin-top: auto; padding: 0.75rem 2rem; border-top: 1px solid var(--line); font-size: var(--t-xs); color: var(--muted); display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; min-height: 2.25rem;}.footer-tagline { white-space: nowrap; }.footer-links { display: flex; gap: 0.5rem; flex-wrap: wrap; }.footer-links a::before { content: "·"; margin-right: 0.5rem; color: var(--muted); }.footer-links a:first-child::before { display: none; }.footer-version { margin-left: auto; white-space: nowrap; }footer a { color: var(--muted); text-decoration-color: var(--line); }footer a:hover { color: var(--ink); text-decoration-color: var(--ink); }
.error-note { margin: 2rem 0; padding: 1rem 1.25rem; background: var(--status-danger-bg); border: 1px solid var(--status-danger-border); color: var(--ink); font-size: var(--t-s);}
/* Resolver hint — small inline feedback below the identity input while a handle is being resolved to its DID. */.resolver-hint { display: none; font-family: 'JetBrains Mono', 'Menlo', monospace; font-size: var(--t-xs); margin: 0.25rem 0 0.5rem; line-height: 1.4;}.resolver-hint.is-loading { display: block; color: var(--muted); font-style: italic; font-family: var(--font-body); }.resolver-hint.is-ok { display: block; color: var(--ink); }.resolver-hint.is-ok::before { content: "→ "; color: var(--accent); font-weight: 700; }.resolver-hint.is-err { display: block; color: var(--accent-ink); }.resolver-hint.is-err::before { content: "⚠ "; }
/* Mobile tightening — the 680px reading column + 2rem padding already mostly handles this, but at narrow widths the masthead is too big and forms get cramped. */@media (max-width: 520px) { .page { padding: 1.5rem 1.25rem 2rem; } .masthead { font-size: 2.25rem; } /* Sub-page masthead must stay smaller than the landing masthead on mobile too — without this rule, the later .masthead size wins by source order (same specificity) and the Round 2 landing-only drop-cap motif dilutes on phones. */ .masthead-sub { font-size: 1.625rem; } .lede { font-size: var(--t-m); margin-bottom: 1rem; } .section { margin-top: 1.25rem; padding-top: 0.75rem; }}
/* Collapsible section disclosure (internal ref). openSectionTitleSummary in web/templates/signup.go sets list-style:none to hide the browser-default triangle so the chevron sits in a known location; we re-add a visible indicator via this ::after pseudo. The marker rotates 90deg in the open state to flip ▸ → ▾ without two different glyphs. Sized to match the title row baseline; spaces away from the rightmost element (the status pill) so it doesn't crowd. */details > summary.section-title-summary::before { content: "▸"; margin-right: 0.5rem; color: var(--muted, #6c7480); font-size: 0.9em; transition: transform 120ms ease; display: inline-block; order: -1; /* leftmost regardless of DOM order inside the flex row */}details[open] > summary.section-title-summary::before { transform: rotate(90deg);}
/* Brand strip — appnav-brand bits + the standalone .brand-strip used on chrome-wrapped unauth pages (signup/contact, verify pending, attest credentials, etc). Mirrors the Astro chrome's brand block in web-frontend/src/styles/globals.css so visual parity holds across the templ/Astro boundary. */.brand-strip { display: flex; align-items: center; margin: 0; padding: 0.75rem 2.5rem 0.65rem; border-bottom: 1px solid var(--line); font-family: var(--font-body); font-size: var(--t-s);}.appnav-brand { display: flex; align-items: center; gap: 0.4rem; text-decoration: none; padding-right: 1rem;}.appnav .appnav-brand { border-right: 1px solid var(--line); margin-right: 0.25rem;}.appnav-brand:hover .appnav-brand-name { color: var(--accent-ink);}.appnav-brand:hover .appnav-brand-mascot { transform: scale(1.06);}.appnav-brand-mascot { height: 1.6rem; width: auto; flex: 0 0 auto; image-rendering: -webkit-optimize-contrast; transition: transform 150ms ease;}.appnav-brand-name { font-family: var(--font-display); font-size: var(--t-l); letter-spacing: -0.03em; color: var(--ink); line-height: 1; transition: color 120ms ease;}.appnav-brand-drop { color: var(--accent);}