sign-free.openapps.xyz

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.
Owned app · rev 528326727848
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.
← All files
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
5283267278 · 5 hours ago
Bounded source sync
15f0fa2e27 · 1 day ago
Bounded source sync
d3aa1ca65b · 1 day ago
Bounded source sync
8e2ca0b773 · 1 day ago
Bounded source sync
5cfa84715c · 1 day ago
Bounded source sync
c849e7b286 · 1 day ago
Bounded source sync
68c1cabe03 · 1 day ago
Bounded source sync
62ae8944f0 · 1 day ago
Bounded source sync
7ed54e7381 · 1 day ago