Source
This app’s code and revision history are public. Download a copy or explore the files below.
Public
The app’s code and revision history are public.
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 1da91c033c738ab74538d13d
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
src/styles.css
/* Sign. Shared look comes from /kit.css; this is the app's own layout. */
body.app-mode .landing-only { display: none !important; }
/* The viewport runs under notches (viewport-fit=cover), so keep content clear of them in landscape. */
body { padding-left: var(--safe-left); padding-right: var(--safe-right); }
/* App pages fill the screen, so the footer never flashes up while a document opens. */
body.app-mode main { min-height: calc(100vh - 64px); min-height: calc(100dvh - 64px); }
.page-pad { padding-block: 56px 80px; }
.narrow { max-width: 640px; }
.small { font-size: 14px; }
.grow { flex: 1; min-width: 0; }
.is-disabled { opacity: .45; pointer-events: none; }
/* What differs between a mouse and a finger. */
.on-coarse { display: none; }
@media (pointer: coarse) { .on-coarse { display: inline; } .on-fine { display: none; } }
.phone-bar { display: none; }
@media (max-width: 720px) {
.hide-phone { display: none !important; }
.phone-bar { display: flex; }
}
.offline { position: fixed; top: calc(72px + var(--safe-top)); left: 50%; z-index: 45; transform: translateX(-50%); width: max-content; max-width: calc(100% - 32px); padding: 9px 14px; border-radius: 999px; background: var(--ink-solid); color: #fff; font: 600 13.5px/1.3 var(--sans); box-shadow: var(--shadow-pop); }
/* Landing hero */
.app-hero { padding: 48px 0 72px; background: linear-gradient(180deg, var(--paper-warm) 0%, var(--paper) 100%); border-bottom: 1px solid #f0ebe1; }
.app-hero-grid { display: grid; grid-template-columns: minmax(0, 1fr) 470px; gap: 56px; align-items: center; }
.app-hero h1 { margin-top: 14px; }
.app-hero .lede { margin-top: 18px; }
.hero-points { list-style: none; padding: 0; margin-top: 26px; display: grid; gap: 10px; font-size: 15.5px; color: #3c4048; }
.hero-points li { display: flex; gap: 10px; align-items: baseline; }
.hero-points li::before { content: ""; flex: 0 0 8px; height: 8px; border-radius: 50%; background: var(--cobalt); transform: translateY(-2px); }
@media (max-width: 960px) { .app-hero-grid { grid-template-columns: minmax(0, 1fr); gap: 32px; } }
/* On phones the start box comes right after the headline, before the selling points. */
@media (max-width: 600px) {
.app-hero { padding: 28px 0 48px; }
.app-hero-grid { gap: 0; }
.hero-text { display: contents; }
#start { order: 1; margin-top: 24px; }
.hero-points { order: 2; margin-top: 28px; }
}
.start { display: grid; grid-template-columns: minmax(0, 1fr); gap: 22px; }
.drop { display: grid; justify-items: center; gap: 12px; padding: 30px 24px 24px; text-align: center; border: 1.5px dashed var(--line-strong); transition: border-color var(--motion-fast) var(--ease-out), background-color var(--motion-fast) var(--ease-out); }
.drop.over { border-color: var(--cobalt); background: var(--cobalt-wash); }
.drop-art { width: 150px; height: auto; }
.drop-title { font: 380 26px/1.15 var(--serif); letter-spacing: -.015em; color: var(--ink-solid); }
.drop-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin-top: 4px; }
.drop .notice { justify-self: stretch; text-align: left; }
@media (pointer: coarse) { .drop { border-style: solid; border-color: var(--line); } }
@media (max-width: 600px) {
.drop { padding: 22px 18px 18px; }
.drop-art { width: 112px; }
.drop-actions { display: grid; grid-template-columns: minmax(0, 1fr); justify-self: stretch; }
}
.your-docs { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; justify-items: start; }
.your-docs ul { list-style: none; padding: 0; display: grid; grid-template-columns: minmax(0, 1fr); justify-self: stretch; }
.your-docs li { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px; min-height: 48px; border-top: 1px solid var(--line); }
.your-docs li:last-child { border-bottom: 1px solid var(--line); }
.your-docs a { display: grid; gap: 2px; padding: 10px 0; color: var(--ink); min-width: 0; }
.doc-name { font-weight: 600; font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.doc-date { font-size: 13px; color: var(--muted); }
@media (hover: hover) { .your-docs a:hover { color: var(--cobalt-ink); } }
.doc-chip-skeleton { width: 76px; height: 24px; border-radius: 999px; }
.tone-done { background: var(--sage-wash); border-color: #cfe2d4; color: #2f5a3c; }
.tone-waiting { background: var(--cobalt-wash); border-color: #d1ddf5; color: var(--cobalt-ink); }
.tone-voided { background: var(--brick-wash); border-color: #efcfc5; color: #7c2f1d; }
.write .h1 { margin-top: 16px; }
.write .lede { margin-top: 12px; }
.write code { font: 500 .85em var(--mono); padding: .1em .35em; border-radius: 5px; background: var(--panel); }
.write-card { margin-top: 24px; padding: 22px; }
.write-text { min-height: max(320px, 50vh); font: 400 17px/1.6 var(--serif); }
.back { display: inline-flex; align-items: center; min-height: 44px; color: var(--muted); font: var(--type-control); }
@media (max-width: 600px) { .write-card { padding: 16px; } .page-pad { padding-block: 28px 56px; } }
/* Landing sections */
.steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; margin-top: 28px; counter-reset: step; padding: 0; }
.steps li { list-style: none; counter-increment: step; }
.steps li::before { content: counter(step); display: grid; place-items: center; width: 34px; height: 34px; margin-bottom: 14px; border-radius: 50%; background: var(--ink-solid); color: #fff; font: 650 15px var(--sans); }
.steps h3 { font: 600 18px/1.3 var(--sans); }
.steps p { margin-top: 8px; color: #4a4e56; }
@media (max-width: 760px) { .steps { grid-template-columns: minmax(0, 1fr); } }
.api-grid { display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); gap: 40px; align-items: start; }
.api-grid .code { font-size: 12.5px; }
@media (max-width: 900px) { .api-grid { grid-template-columns: minmax(0, 1fr); } }
.more-apps { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; list-style: none; padding: 0; margin-top: 22px; }
.more-apps a { display: grid; gap: 4px; padding: 16px 18px; border: 1px solid var(--line); border-radius: 14px; background: #fff; color: var(--ink); transition: border-color var(--motion-fast) var(--ease-out), box-shadow var(--motion-fast) var(--ease-out); }
@media (hover: hover) { .more-apps a:hover { border-color: var(--line-strong); box-shadow: var(--shadow); color: var(--ink); } }
.more-apps strong { font: 400 22px/1.1 var(--serif); }
.more-apps span { color: var(--muted); font-size: 14px; }
.compare td:first-child { font-weight: 600; }
.compare td, .compare th { min-width: 120px; }
.legal-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; margin-top: 24px; }
.legal-grid p { margin-top: 8px; color: #4a4e56; }
@media (max-width: 820px) { .legal-grid { grid-template-columns: minmax(0, 1fr); } }
/* Page-level empty and error states use an h1 */
:where(.empty-state, .error-state) > h1 { font: var(--type-title); letter-spacing: -.02em; color: var(--ink-solid); text-wrap: balance; }
:where(.error-state) > h1 { color: #7c2f1d; }
/* Document pages */
.doc-head { border-bottom: 1px solid var(--line); background: linear-gradient(180deg, var(--paper-warm), var(--paper)); }
.doc-head-inner { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px 20px; flex-wrap: wrap; padding: 26px 0 22px; }
.doc-title { margin-top: 6px; font: 360 clamp(28px, 3.4vw, 40px)/1.08 var(--serif); letter-spacing: -.025em; color: var(--ink-solid); text-wrap: balance; }
.title-input { display: block; width: 100%; margin-top: 4px; padding: 2px 0; border: 0; border-bottom: 1px dashed transparent; border-radius: 0; background: transparent; font: 360 clamp(28px, 3.4vw, 40px)/1.08 var(--serif); letter-spacing: -.025em; color: var(--ink-solid); text-overflow: ellipsis; }
@media (hover: hover) { .title-input:hover { border-bottom-color: var(--line-strong); } }
.title-input:focus { outline: none; border-bottom-color: var(--cobalt); }
.head-actions { display: flex; align-items: center; gap: 10px; }
.status-done { color: #2f6b45; }
.status-voided { color: var(--brick); }
.status-waiting { color: var(--cobalt-ink); }
@media (max-width: 720px) {
.doc-head-inner { flex-wrap: nowrap; align-items: flex-start; padding: 18px 0 16px; }
.doc-title, .title-input { font-size: 28px; }
}
.doc-body { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 28px; align-items: start; padding-top: 24px; padding-bottom: 80px; }
.doc-side { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; position: sticky; top: calc(84px + var(--safe-top)); max-height: calc(100vh - 100px); overflow-y: auto; overscroll-behavior: contain; padding: 2px 2px 8px; }
.side-card { padding: 18px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
.done-card { padding: 18px; display: grid; gap: 6px; background: var(--sage-wash); border-color: #cfe2d4; color: #2f5a3c; box-shadow: none; }
.done-card .h3 { color: #24452f; }
.voided-card { background: var(--brick-wash); border-color: #efcfc5; color: #7c2f1d; box-shadow: none; }
@media (max-width: 960px) {
.doc-body { grid-template-columns: minmax(0, 1fr); gap: 20px; padding-top: 18px; }
.doc-side { position: static; max-height: none; overflow: visible; order: -1; padding: 0; }
}
.sign-body { padding-top: 22px; padding-bottom: 80px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; max-width: 920px; }
.sign-intro { display: grid; gap: 10px; }
.sign-message { padding: 12px 16px; border-left: 3px solid var(--cobalt); background: #fff; border-radius: 0 12px 12px 0; font: 400 17px/1.5 var(--serif); color: var(--ink); white-space: pre-line; }
.progress { white-space: nowrap; }
.doc > .action-bar { padding-inline: max(16px, var(--safe-left)) max(16px, var(--safe-right)); }
.doc > .action-bar .progress { flex: 0 0 auto; }
.pages { display: grid; grid-template-columns: minmax(0, 1fr); gap: 22px; }
.page-wrap { display: grid; gap: 6px; }
.page { position: relative; width: 100%; background: #fff; border-radius: 4px; box-shadow: 0 1px 2px #1a1d2414, 0 10px 30px -14px #1a1d2440; overflow: hidden; }
.page canvas { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; transition: opacity var(--motion) var(--ease-out); }
.page canvas.drawn { opacity: 1; }
.page-layer { position: absolute; inset: 0; }
.pages.placing .page-layer { cursor: crosshair; }
.page-num { text-align: center; font-size: 12.5px; color: var(--faint); }
.page-placeholder { aspect-ratio: 8.5 / 11; }
.page-placeholder .skeleton { position: absolute; inset: 10% 12% auto; height: 22%; border-radius: 6px; opacity: .7; }
.placing-hint { position: sticky; top: calc(72px + var(--safe-top)); z-index: 5; display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; padding: 8px 8px 8px 14px; border-radius: 12px; background: var(--ink-solid); color: #fff; font: 600 14px/1.35 var(--sans); box-shadow: var(--shadow-pop); }
.placing-hint .btn { color: #fff; flex: 0 0 auto; }
@media (hover: hover) { .placing-hint .btn:hover { background: #ffffff1f; color: #fff; } }
.fieldbox { container-type: size; position: absolute; display: flex; align-items: center; padding: 0 5px; border: 1.5px solid var(--c); border-radius: 4px; background: color-mix(in srgb, var(--c) 12%, transparent); color: var(--c); overflow: visible; user-select: none; -webkit-user-select: none; touch-action: none; }
.fieldbox-label { font: 650 clamp(6.5px, 48cqh, 12px)/1 var(--sans); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; pointer-events: none; }
.fieldbox.editable { cursor: grab; transition: box-shadow var(--motion-fast) var(--ease-out); }
.fieldbox.editable:active { cursor: grabbing; }
.fieldbox.selected { z-index: 2; box-shadow: 0 0 0 3px color-mix(in srgb, var(--c) 25%, transparent); }
.fieldbox:focus-visible { outline: 2px solid var(--cobalt); outline-offset: 2px; }
.fieldbox-del { position: absolute; top: -30px; right: -2px; display: grid; place-items: center; width: 24px; height: 24px; padding: 0; border: 2px solid #fff; border-radius: 50%; background: var(--c); color: #fff; font: 600 14px/1 var(--sans); cursor: pointer; }
.fieldbox-resize { position: absolute; right: -7px; bottom: -7px; width: 14px; height: 14px; border: 2px solid #fff; border-radius: 4px; background: var(--c); cursor: nwse-resize; }
@media (pointer: coarse) {
.fieldbox-del::before { content: ""; position: absolute; inset: -10px; }
.fieldbox-resize::before { content: ""; position: absolute; inset: -12px; }
}
.fieldbox.filled { border-style: dashed; background: transparent; touch-action: auto; }
.fieldbox.filled.has-value, .fieldbox.mine.has-value { border-color: transparent; background: transparent; }
.fieldbox img { max-width: 100%; max-height: 100%; object-fit: contain; object-position: left center; pointer-events: none; }
.fill-text { color: #14244f; font: 500 clamp(6px, 62cqh, 15px)/1 var(--sans); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fieldbox.mine { cursor: pointer; touch-action: manipulation; background: color-mix(in srgb, var(--c) 16%, #fffc); animation: pulse 2.2s ease-in-out infinite; }
.fieldbox.mine.has-value, .fieldbox.mine.auto { animation: none; }
.fieldbox.mine.auto { cursor: default; border-style: dashed; }
.fieldbox.mine.has-value { box-shadow: inset 0 -1.5px 0 color-mix(in srgb, var(--c) 45%, transparent); }
/* Checkboxes: the mark fills the box, the label sits beside it, and the signer's box gets a finger-sized hit area. */
.fieldbox.checkbox { justify-content: center; padding: 0; }
.fieldbox.checkbox .fill-text { overflow: visible; font-size: max(9px, 85cqh); }
.fieldbox.checkbox.has-value { border-color: var(--c); box-shadow: none; }
.fieldbox.mine.checkbox::before { content: ""; position: absolute; inset: min(0px, (100% - 44px) / 2); }
.fieldbox-side { position: absolute; top: 50%; left: calc(100% + 10px); width: max-content; max-width: 200px; padding: 2px 6px; border-radius: 4px; background: #fffe; color: var(--c); font: 600 12px/1.25 var(--sans); transform: translateY(-50%); pointer-events: none; }
.fieldbox-side.before { left: auto; right: calc(100% + 10px); text-align: right; }
.fieldbox.mine .fieldbox-side { pointer-events: auto; cursor: pointer; }
@keyframes pulse { 50% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--c) 22%, transparent); } }
.signer-list, .status-list, .events { list-style: none; padding: 0; display: grid; grid-template-columns: minmax(0, 1fr); }
.signer-list li { display: flex; align-items: center; gap: 4px; border-radius: 10px; transition: background-color var(--motion-fast) var(--ease-out); }
.signer-list li.active { background: var(--panel); }
.signer-pick { flex: 1; display: flex; align-items: center; gap: 10px; min-width: 0; min-height: 44px; padding: 8px 10px; border: 0; background: none; color: var(--ink); text-align: left; cursor: pointer; font-size: 14.5px; line-height: 1.3; }
.signer-pick:disabled { cursor: default; }
.signer-pick strong { font-weight: 600; }
.signer-email { display: block; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.signer-name { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.dot { flex: 0 0 10px; width: 10px; height: 10px; border-radius: 50%; }
.add-signer { padding-top: 12px; border-top: 1px solid var(--line); }
.signer-list:empty + .add-signer, .h3 + .add-signer { padding-top: 0; border-top: 0; }
.field-palette { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.palette-btn { display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 12px; border: 1px solid var(--line-strong); border-radius: 10px; background: #fff; cursor: pointer; font: var(--type-control); color: var(--ink); text-align: left; transition: border-color var(--motion-fast) var(--ease-out), background-color var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out); }
@media (hover: hover) { .palette-btn:hover:not(:disabled) { border-color: #b5bdc8; } }
.palette-btn.on { background: var(--ink-solid); border-color: var(--ink-solid); color: #fff; }
.palette-btn:disabled { opacity: .45; cursor: not-allowed; }
.field-icon { flex: 0 0 auto; color: var(--muted); }
.palette-btn.on .field-icon { color: #fff; }
.status-list li { display: grid; gap: 6px; padding: 12px 0; border-top: 1px solid var(--line); }
.status-list li:first-child { border-top: 0; padding-top: 2px; }
.link-actions { --gap: 6px; margin-top: 2px; }
/* A signer's menu opens under their row and stays inside the card, whatever the name's length. */
.status-list li { position: relative; }
.link-actions .dropdown { position: static; }
.link-actions .dropdown-menu { max-width: 100%; }
.events li { display: flex; justify-content: space-between; gap: 10px; padding: 7px 0; border-top: 1px solid var(--line); font-size: 13.5px; }
.events li:first-child { border-top: 0; }
.fingerprint code { font: 12px var(--mono); }
/* Signature pad */
.sigpad { position: relative; height: 190px; border: 1px solid var(--line-strong); border-radius: 12px; background: #fff; overflow: hidden; }
.sigpad canvas { position: absolute; inset: 0; width: 100%; height: 100%; touch-action: none; cursor: crosshair; }
.sigpad-line { position: absolute; left: 24px; right: 24px; bottom: 44px; height: 1px; background: var(--line-strong); pointer-events: none; }
.sigpad-hint { position: absolute; left: 0; right: 0; bottom: 18px; text-align: center; color: var(--faint); font-size: 13px; pointer-events: none; }
.sigpad-typed { display: grid; place-items: center; height: 130px; }
.sigpad-typed span { font: italic 380 54px/1 var(--serif); color: #14244f; }
.consent { align-items: flex-start; font-size: 15.5px; line-height: 1.5; }
.consent input { margin-top: 3px; flex: 0 0 18px; }
.segmented { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; padding: 4px; border-radius: 12px; background: var(--panel); border: 1px solid var(--panel-line); }
.segmented-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.segmented button { min-height: 40px; border: 0; border-radius: 9px; background: transparent; cursor: pointer; font: var(--type-control); color: var(--muted); transition: background-color var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-out), box-shadow var(--motion-fast) var(--ease-out); }
.segmented button[aria-checked="true"] { background: #fff; color: var(--ink-solid); box-shadow: 0 1px 3px #0000001a; }
@media (pointer: coarse) { .segmented button { min-height: 44px; } }
Change history
Quality pass: phone signing, edit signers, copy to send again
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync