@panphora/clayjs 1.12.0 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- /* clayjs 1.12.0 standalone build: every clayjs module in one file. https://clayjs.com/offline
1
+ /* clayjs 1.12.1 standalone build: every clayjs module in one file. https://clayjs.com/offline
2
2
  Third-party code inside keeps its own license (Sortable MIT, Squire MIT, DOMPurify Apache-2.0 OR MPL-2.0, MicroModal MIT, parse5 MIT): https://clayjs.com/THIRD-PARTY-NOTICES.md */
3
3
  (() => {
4
4
  var __create = Object.create;
@@ -15193,7 +15193,7 @@
15193
15193
  this._log("applyUpdate - pausing mutations and morphing");
15194
15194
  this.isPaused = true;
15195
15195
  const scrollX = window.scrollX;
15196
- const scrollY = window.scrollY;
15196
+ const scrollY2 = window.scrollY;
15197
15197
  mutation_default.pause();
15198
15198
  pauseGate();
15199
15199
  let diverged = false;
@@ -15231,7 +15231,7 @@
15231
15231
  });
15232
15232
  diverged = report2.localDiverged;
15233
15233
  typedDuringWait = typed;
15234
- window.scrollTo(scrollX, scrollY);
15234
+ window.scrollTo(scrollX, scrollY2);
15235
15235
  this._setPeerBase(html, identityMap, ticket);
15236
15236
  this._applyGen++;
15237
15237
  if (!(this._acceptedSaveTicket > ticket)) {
@@ -15282,7 +15282,7 @@
15282
15282
  this._log(`applyExternal - external disk change (seq=${seq})`);
15283
15283
  this.isPaused = true;
15284
15284
  const scrollX = window.scrollX;
15285
- const scrollY = window.scrollY;
15285
+ const scrollY2 = window.scrollY;
15286
15286
  mutation_default.pause();
15287
15287
  pauseGate();
15288
15288
  let diverged = false;
@@ -15325,7 +15325,7 @@
15325
15325
  diverged = report2.localDiverged;
15326
15326
  typedDuringWait = typed;
15327
15327
  this._setDiskBase(html, ticket);
15328
- window.scrollTo(scrollX, scrollY);
15328
+ window.scrollTo(scrollX, scrollY2);
15329
15329
  if (!(this._acceptedSaveTicket > ticket)) {
15330
15330
  if (typeof etag === "string" && etag) {
15331
15331
  recordEtag(etag);
@@ -35967,14 +35967,22 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
35967
35967
  transition: bottom .25s ease, opacity .2s ease;
35968
35968
  pointer-events: none;
35969
35969
  }
35970
- .hcp[hidden], .hcp[data-hcp-state="dismissed"], .hcp[data-hcp-state="off"], .hcp[data-hcp-intro] { display: none; }
35970
+ .hcp[hidden], .hcp[data-hcp-state="dismissed"], .hcp[data-hcp-state="off"] { display: none; }
35971
35971
  .hcp[data-hcp-typing] { opacity: 0; visibility: hidden; }
35972
35972
  .hcp > * { pointer-events: auto; }
35973
- .hcp svg { display: block; flex: none; }
35973
+ .hcp svg {
35974
+ display: block; flex: none; width: 16px; height: 16px; line-height: 1;
35975
+ fill: none; stroke: none; stroke-width: 0; stroke-linecap: butt; stroke-linejoin: miter;
35976
+ }
35977
+ .hcp .hcp-x svg, .hcp .hcp-actions .hcp-btn svg, .hcp-tab svg, .hcp-file svg { fill: currentColor; }
35978
+ .hcp .hcp-file svg { width: 20px; height: 20px; }
35979
+ .hcp .hcp-tab svg { width: 16px; height: 18px; }
35980
+ .hcp .hcp-dock .hcp-x svg { width: 12px; height: 12px; }
35981
+ .hcp button, .hcp a { border-radius: 0; line-height: 1.5; }
35974
35982
 
35975
35983
  .hcp-btn {
35976
35984
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
35977
- height: 34px; padding: 0 14px;
35985
+ height: 34px; min-height: 0; padding: 0 14px;
35978
35986
  font-family: var(--hcp-sans); font-size: 14px; font-weight: 500; line-height: 1.5;
35979
35987
  white-space: nowrap; text-decoration: none; cursor: pointer; user-select: none;
35980
35988
  color: var(--hcp-ink); background: var(--hcp-face);
@@ -35982,7 +35990,7 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
35982
35990
  border-color: var(--hcp-edge-hi) var(--hcp-edge-lo) var(--hcp-edge-lo) var(--hcp-edge-hi);
35983
35991
  outline: none;
35984
35992
  }
35985
- .hcp-btn:hover { background: color-mix(in srgb, var(--hcp-face), var(--hcp-edge-hi) 45%); color: var(--hcp-ink); }
35993
+ .hcp .hcp-btn:hover { background: color-mix(in srgb, var(--hcp-face), var(--hcp-edge-hi) 45%); color: var(--hcp-ink); }
35986
35994
  .hcp-btn:active { border-color: var(--hcp-edge-lo) var(--hcp-edge-hi) var(--hcp-edge-hi) var(--hcp-edge-lo); }
35987
35995
  .hcp-btn:active > span { translate: 1px 1px; }
35988
35996
  .hcp-btn > span { display: inline-flex; align-items: center; gap: 7px; }
@@ -35993,18 +36001,18 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
35993
36001
  --hcp-edge-lo: color-mix(in srgb, var(--hcp-ink), black 32%);
35994
36002
  color: var(--hcp-ground);
35995
36003
  }
35996
- .hcp-btn--primary:hover { background: color-mix(in srgb, var(--hcp-ink), var(--hcp-ground) 12%); color: var(--hcp-ground); }
36004
+ .hcp .hcp-btn--primary:hover { background: color-mix(in srgb, var(--hcp-ink), var(--hcp-ground) 12%); color: var(--hcp-ground); }
35997
36005
 
35998
36006
  .hcp-dock { display: flex; align-items: stretch; box-shadow: 0 6px 16px -8px rgba(43, 36, 27, .45); }
35999
36007
  .hcp-tab { font-size: 13.5px; padding: 0 12px 0 10px; }
36000
36008
  .hcp-tab svg { color: var(--hcp-brass); }
36001
36009
  .hcp-dock .hcp-x {
36002
- width: 26px; height: 34px; display: inline-flex; align-items: center; justify-content: center;
36010
+ width: 26px; height: 34px; min-height: 0; border-radius: 0; display: inline-flex; align-items: center; justify-content: center;
36003
36011
  background: var(--hcp-face); color: var(--hcp-muted); cursor: pointer;
36004
36012
  border: 2px solid; border-left: 0;
36005
36013
  border-color: var(--hcp-edge-hi) var(--hcp-edge-lo) var(--hcp-edge-lo) var(--hcp-edge-hi);
36006
36014
  }
36007
- .hcp-dock .hcp-x:hover { color: var(--hcp-ink); }
36015
+ .hcp .hcp-dock .hcp-x:hover { color: var(--hcp-ink); background: var(--hcp-face); }
36008
36016
  .hcp-tab__label { display: inline; }
36009
36017
  .hcp[data-hcp-state="mini"] .hcp-tab__label,
36010
36018
  .hcp[data-hcp-state="mini"] .hcp-dock .hcp-x { display: none; }
@@ -36022,11 +36030,13 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36022
36030
  @keyframes hcp-rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
36023
36031
 
36024
36032
  .hcp-card .hcp-x {
36025
- position: absolute; top: 10px; right: 10px; width: 28px; height: 28px;
36033
+ position: absolute; top: 12px; right: 12px; width: 24px; height: 24px; min-height: 0;
36026
36034
  display: inline-flex; align-items: center; justify-content: center;
36035
+ border: 1px solid var(--hcp-line-2); border-radius: 3px; background: var(--hcp-surface);
36027
36036
  color: var(--hcp-muted); cursor: pointer;
36028
36037
  }
36029
- .hcp-card .hcp-x:hover { color: var(--hcp-ink); background: var(--hcp-sunk); }
36038
+ .hcp .hcp-card .hcp-x:hover { color: var(--hcp-ink); border-color: var(--hcp-muted); background: var(--hcp-surface); }
36039
+ .hcp .hcp-card .hcp-x svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 2; }
36030
36040
  .hcp-kicker {
36031
36041
  display: flex; align-items: center; gap: 8px;
36032
36042
  font-family: var(--hcp-mono); font-size: 11px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase;
@@ -36054,14 +36064,29 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36054
36064
  .hcp-file small { display: block; font-size: 12px; color: var(--hcp-muted); line-height: 1.4; }
36055
36065
  .hcp-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
36056
36066
  .hcp-actions .hcp-btn--primary { flex: 1 1 auto; }
36067
+ .hcp-signup { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--hcp-line); }
36068
+ .hcp-signup label { display: block; font-size: 13px; line-height: 1.45; color: var(--hcp-ink-2); margin-bottom: 8px; }
36069
+ .hcp-signup-row { display: flex; gap: 8px; }
36070
+ .hcp-signup-row[hidden] { display: none; }
36071
+ .hcp-signup input[type="email"] {
36072
+ flex: 1 1 auto; min-width: 0; height: 34px; padding: 0 10px; margin: 0;
36073
+ font: 14px var(--hcp-sans); color: var(--hcp-ink); background: var(--hcp-surface);
36074
+ border: 1px solid var(--hcp-line-2); border-radius: 0; box-shadow: none;
36075
+ }
36076
+ .hcp-signup input[type="email"]:focus-visible { outline: 2px solid var(--hcp-brass); outline-offset: 1px; }
36077
+ .hcp-hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
36078
+ .hcp-msg { margin-top: 8px; font-size: 13px; color: var(--hcp-ink-2); }
36079
+ .hcp[data-hcp-reason="error"] .hcp-signup { display: none; }
36080
+ @media (max-width: 360px) { .hcp-signup-row { flex-direction: column; } }
36057
36081
  .hcp-foot { margin-top: 12px; display: flex; justify-content: space-between; align-items: center; gap: 10px; }
36058
36082
  .hcp-foot small { font-size: 12px; color: var(--hcp-muted); }
36059
36083
  .hcp-quiet {
36084
+ min-height: 0; border-radius: 0;
36060
36085
  font-size: 12px; color: var(--hcp-muted); cursor: pointer;
36061
36086
  text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--hcp-line-2);
36062
36087
  white-space: nowrap;
36063
36088
  }
36064
- .hcp-quiet:hover { color: var(--hcp-ink); }
36089
+ .hcp .hcp-quiet:hover { color: var(--hcp-ink); background: none; }
36065
36090
 
36066
36091
  @media (max-width: 480px) {
36067
36092
  .hcp { right: 12px; bottom: calc(12px + var(--hcp-lift)); }
@@ -36070,7 +36095,7 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36070
36095
  }
36071
36096
  @media (pointer: coarse) {
36072
36097
  .hcp-btn, .hcp-dock .hcp-x, .hcp-card .hcp-x { min-height: 44px; }
36073
- .hcp-card .hcp-x { width: 44px; }
36098
+ .hcp-card .hcp-x { width: 44px; height: 44px; top: 6px; right: 6px; }
36074
36099
  .hcp-quiet { display: inline-flex; align-items: center; min-height: 44px; }
36075
36100
  }
36076
36101
  @media (prefers-reduced-motion: reduce) {
@@ -36087,8 +36112,43 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36087
36112
  }
36088
36113
  });
36089
36114
 
36115
+ // src/plugins/visitor-drafts/bottom-ui.js
36116
+ function announceBottomUi() {
36117
+ document.dispatchEvent(new CustomEvent(BOTTOM_UI_CHANGED));
36118
+ }
36119
+ function bottomBarHeight(x3, skip) {
36120
+ const h = window.innerHeight;
36121
+ let raise = 0;
36122
+ const hits = document.elementsFromPoint ? document.elementsFromPoint(x3, h - 3) : [];
36123
+ for (const hit of hits) {
36124
+ for (let el5 = hit; el5 && el5 !== document.body && el5 !== document.documentElement; el5 = el5.parentElement) {
36125
+ if (skip(el5)) break;
36126
+ const position = getComputedStyle(el5).position;
36127
+ if (position === "fixed" || position === "sticky") {
36128
+ const height = Math.ceil(h - el5.getBoundingClientRect().top);
36129
+ if (height < h / 3) raise = Math.max(raise, height);
36130
+ break;
36131
+ }
36132
+ }
36133
+ }
36134
+ return raise;
36135
+ }
36136
+ function promptPanel(box) {
36137
+ const panel2 = document.querySelector("#hcp:not([hidden])");
36138
+ if (!panel2) return 0;
36139
+ const r = panel2.getBoundingClientRect();
36140
+ if (!r.width || !r.height || r.right <= box.left || r.left >= box.right) return 0;
36141
+ return Math.ceil(window.innerHeight - r.top);
36142
+ }
36143
+ var BOTTOM_UI_CHANGED;
36144
+ var init_bottom_ui = __esm({
36145
+ "src/plugins/visitor-drafts/bottom-ui.js"() {
36146
+ BOTTOM_UI_CHANGED = "clay:bottom-ui-changed";
36147
+ }
36148
+ });
36149
+
36090
36150
  // src/plugins/visitor-drafts/prompt.js
36091
- function mountPrompt({ memory, appName, link: link2, onError: onError2 }) {
36151
+ function mountPrompt({ memory, appName, link: link2, tag, source: source3 }) {
36092
36152
  if (!document.getElementById("hcp-style")) {
36093
36153
  document.head.insertAdjacentHTML("beforeend", `<link rel="stylesheet" clay="editor-ui" href="${FONT_HREF}">
36094
36154
  <style clay="editor-ui" id="hcp-style">${PROMPT_CSS}</style>`);
@@ -36101,8 +36161,33 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36101
36161
  const USES_TO_SHOW = 3;
36102
36162
  const IDLE_MS = 2500;
36103
36163
  const TEXTY = /^(INPUT|TEXTAREA|SELECT)$/;
36164
+ const OUR_UI = "#hcp, .clay-intro, .clay-owner";
36104
36165
  const linkEl = root3.querySelector("[data-hcp-link]");
36105
36166
  linkEl.href = link2;
36167
+ const signup = root3.querySelector("[data-hcp-signup]");
36168
+ if (signup) {
36169
+ const email = signup.querySelector("#hcp-email");
36170
+ const honey = signup.querySelector(".hcp-hp");
36171
+ const row = signup.querySelector(".hcp-signup-row");
36172
+ const message = signup.querySelector(".hcp-msg");
36173
+ signup.addEventListener("submit", (event) => {
36174
+ event.preventDefault();
36175
+ fetch("/_/newsletter/subscribe", {
36176
+ method: "POST",
36177
+ headers: { "Content-Type": "application/json" },
36178
+ credentials: "same-origin",
36179
+ body: JSON.stringify({ email: email.value.trim(), tags: [tag], source: source3, website: honey.value })
36180
+ }).then((response) => {
36181
+ if (!response.ok) throw new Error("signup failed");
36182
+ row.hidden = true;
36183
+ message.textContent = SIGNUP_COPY.thanks;
36184
+ message.hidden = false;
36185
+ }).catch(() => {
36186
+ message.textContent = SIGNUP_COPY.failed;
36187
+ message.hidden = false;
36188
+ });
36189
+ });
36190
+ }
36106
36191
  if (appName) root3.querySelector("[data-hcp-name]").textContent = appName;
36107
36192
  const tab = root3.querySelector("[data-hcp=open]");
36108
36193
  function set3(state2, reason) {
@@ -36117,7 +36202,7 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36117
36202
  lift();
36118
36203
  }
36119
36204
  function isHostField(el5) {
36120
- return el5 && !root3.contains(el5) && (TEXTY.test(el5.tagName) || el5.isContentEditable);
36205
+ return el5 && !root3.contains(el5) && !el5.closest(OUR_UI) && (TEXTY.test(el5.tagName) || el5.isContentEditable);
36121
36206
  }
36122
36207
  let timer = null;
36123
36208
  function maybeShow(reason) {
@@ -36156,20 +36241,10 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36156
36241
  if (liftFrame) return;
36157
36242
  liftFrame = requestAnimationFrame(() => {
36158
36243
  liftFrame = 0;
36159
- const y2 = innerHeight - 3, x3 = innerWidth - 24;
36160
- let raise = 0;
36161
- const hits = document.elementsFromPoint ? document.elementsFromPoint(x3, y2) : [];
36162
- for (let i2 = 0; i2 < hits.length; i2++) {
36163
- for (let el5 = hits[i2]; el5 && el5 !== document.body && el5 !== document.documentElement; el5 = el5.parentElement) {
36164
- if (root3.contains(el5) || el5.closest("[data-hcp-preview]")) break;
36165
- const pos = getComputedStyle(el5).position;
36166
- if (pos === "fixed" || pos === "sticky") {
36167
- raise = Math.max(raise, Math.ceil(innerHeight - el5.getBoundingClientRect().top));
36168
- break;
36169
- }
36170
- }
36171
- }
36172
- root3.style.setProperty("--hcp-lift", (raise > 0 && raise < innerHeight / 3 ? raise : 0) + "px");
36244
+ const raise = bottomBarHeight(innerWidth - 24, (el5) => root3.contains(el5) || el5.closest("[data-hcp-preview], .clay-owner"));
36245
+ const next = raise + "px";
36246
+ if (root3.style.getPropertyValue("--hcp-lift") !== next) root3.style.setProperty("--hcp-lift", next);
36247
+ announceBottomUi();
36173
36248
  });
36174
36249
  }
36175
36250
  function downloadCurrent() {
@@ -36230,11 +36305,7 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36230
36305
  function clearError() {
36231
36306
  if (root3.getAttribute("data-hcp-reason") === "error") root3.setAttribute("data-hcp-reason", "use");
36232
36307
  }
36233
- function hideForIntro(on2) {
36234
- if (on2) root3.setAttribute("data-hcp-intro", "");
36235
- else root3.removeAttribute("data-hcp-intro");
36236
- }
36237
- const api = { set: set3, root: root3, showError, clearError, hideForIntro };
36308
+ const api = { set: set3, root: root3, showError, clearError };
36238
36309
  if (mem.dismissed) {
36239
36310
  root3.setAttribute("data-hcp-state", "dismissed");
36240
36311
  return api;
@@ -36250,30 +36321,41 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36250
36321
  if (!mem.shown && (mem.uses || 0) >= USES_TO_SHOW) maybeShow("return");
36251
36322
  return api;
36252
36323
  }
36253
- var FONT_HREF, ASIDE;
36324
+ var SIGNUP_COPY, FONT_HREF, ASIDE;
36254
36325
  var init_prompt = __esm({
36255
36326
  "src/plugins/visitor-drafts/prompt.js"() {
36256
36327
  init_prompt_style();
36328
+ init_bottom_ui();
36329
+ SIGNUP_COPY = {
36330
+ thanks: "Thanks. Check your email for a link to confirm.",
36331
+ failed: "That didn't go through. Check the address and try again."
36332
+ };
36257
36333
  FONT_HREF = "https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@500&family=IBM+Plex+Sans:wght@400;500;600&family=Newsreader:opsz,wght@6..72,500&display=swap";
36258
36334
  ASIDE = `<aside class="hcp" id="hcp" hidden aria-label="Download this app" data-hcp-state="tab" data-hcp-reason="open" sap-ignore clay="editor-ui">
36259
36335
  <section class="hcp-card" id="hcp-card" role="dialog" aria-modal="false" aria-labelledby="hcp-title">
36260
- <button type="button" class="hcp-x" data-hcp="minimize" aria-label="Minimize"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M3 12h10v2H3z"/></svg></button>
36336
+ <button type="button" class="hcp-x" data-hcp="minimize" aria-label="Minimize"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" aria-hidden="true"><path d="M5 12h14"/></svg></button>
36261
36337
  <div class="hcp-kicker">Free download</div>
36262
- <h2 class="hcp-title" id="hcp-title"><span data-hcp-for="use">Your numbers are saved in this browser only.</span><span data-hcp-for="open">This app is free to keep.</span><span data-hcp-for="return">Your numbers are saved in this browser only.</span><span data-hcp-for="error">Your work isn't being saved in this browser.</span></h2>
36263
- <p class="hcp-body"><span data-hcp-for="open">Download it as one file and use it on your computer, no account needed.</span><span data-hcp-for="use">Download the file to keep them on your computer for good.</span><span data-hcp-for="return">Download the file to keep them on your computer for good.</span><span data-hcp-for="error">Storage is full or turned off here. Download the file to keep what you've done.</span></p>
36338
+ <h2 class="hcp-title" id="hcp-title"><span data-hcp-for="use">Your work is saved in this browser only.</span><span data-hcp-for="open">This app is free to keep.</span><span data-hcp-for="return">Your work is saved in this browser only.</span><span data-hcp-for="error">Your work isn't being saved in this browser.</span></h2>
36339
+ <p class="hcp-body"><span data-hcp-for="open">Download it as one file and use it on your computer, no account needed.</span><span data-hcp-for="use">Download the file to keep it on your computer for good.</span><span data-hcp-for="return">Download the file to keep it on your computer for good.</span><span data-hcp-for="error">Storage is full or turned off here. Download the file to keep what you've done.</span></p>
36264
36340
  <div class="hcp-file">
36265
- <svg width="26" height="30" viewBox="0 0 26 30" fill="none" aria-hidden="true"><path d="M2 1h15l7 7v21H2z" fill="var(--hcp-surface)" stroke="currentColor" stroke-width="2"/><path d="M17 1v7h7" stroke="currentColor" stroke-width="2"/><path d="M7 15h12M7 19h12M7 23h8" stroke="var(--hcp-muted)" stroke-width="2"/></svg>
36266
- <div><b class="hcp-name" data-hcp-name>This app</b><small>One file with the whole app and your numbers in it</small></div>
36341
+ <svg width="20" height="20" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M224,144v64a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V144a8,8,0,0,1,16,0v56H208V144a8,8,0,0,1,16,0Zm-101.66,5.66a8,8,0,0,0,11.32,0l40-40a8,8,0,0,0-11.32-11.32L136,124.69V32a8,8,0,0,0-16,0v92.69L93.66,98.34a8,8,0,0,0-11.32,11.32Z"/></svg>
36342
+ <div><b class="hcp-name" data-hcp-name>This app</b><small>One file with the whole app and your work in it</small></div>
36267
36343
  </div>
36268
- <p class="hcp-body">Open it with HTML Clay, a free app for Mac, Windows and Linux. It opens the file in a window and saves every change into it, so your numbers stay on your computer.</p>
36344
+ <p class="hcp-body">Open it with HTML Clay, a free app for Mac, Windows and Linux. It opens the file in a window and saves every change into it, so your work stays on your computer.</p>
36269
36345
  <div class="hcp-actions">
36270
- <a class="hcp-btn hcp-btn--primary" data-hcp-link href="/_/download?as=htmlclay"><span><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M7 1h2v8.6l2.8-2.8 1.4 1.4L8 13.4 2.8 8.2l1.4-1.4L7 9.6zM2 13h12v2H2z"/></svg>Download free</span></a>
36346
+ <a class="hcp-btn hcp-btn--primary" data-hcp-link href="/_/download?as=htmlclay"><span><svg width="16" height="16" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M224,144v64a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V144a8,8,0,0,1,16,0v56H208V144a8,8,0,0,1,16,0Zm-101.66,5.66a8,8,0,0,0,11.32,0l40-40a8,8,0,0,0-11.32-11.32L136,124.69V32a8,8,0,0,0-16,0v92.69L93.66,98.34a8,8,0,0,0-11.32,11.32Z"/></svg>Download free</span></a>
36271
36347
  <button type="button" class="hcp-btn" data-hcp="minimize"><span>Not now</span></button>
36272
36348
  </div>
36349
+ <form class="hcp-signup" data-hcp-signup novalidate>
36350
+ <label for="hcp-email">I make one of these about every two weeks. Get the next one by email.</label>
36351
+ <div class="hcp-signup-row"><input id="hcp-email" type="email" autocomplete="email" required placeholder="you@example.com"><button type="submit" class="hcp-btn"><span>Send me the next one</span></button></div>
36352
+ <input class="hcp-hp" name="website" tabindex="-1" autocomplete="off" aria-hidden="true">
36353
+ <p class="hcp-msg" role="status" hidden></p>
36354
+ </form>
36273
36355
  <div class="hcp-foot"><small>Free, and the file is yours to keep.</small><button type="button" class="hcp-quiet" data-hcp="dismiss">Don&rsquo;t show again</button></div>
36274
36356
  </section>
36275
36357
  <div class="hcp-dock">
36276
- <button type="button" class="hcp-btn hcp-tab" data-hcp="open" aria-controls="hcp-card" aria-expanded="false" aria-label="This app is free to keep"><span><svg width="16" height="18" viewBox="0 0 16 18" fill="none" aria-hidden="true"><path d="M1.5 1h8.5l4.5 4.5V17h-13z" stroke="currentColor" stroke-width="2"/><path d="M10 1v5h4.5" stroke="currentColor" stroke-width="2"/><path d="M8 8v6M5.5 11.5 8 14l2.5-2.5" stroke="currentColor" stroke-width="1.8"/></svg><span class="hcp-tab__label">This app is free to keep</span></span></button>
36358
+ <button type="button" class="hcp-btn hcp-tab" data-hcp="open" aria-controls="hcp-card" aria-expanded="false" aria-label="This app is free to keep"><span><svg width="16" height="16" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M224,144v64a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V144a8,8,0,0,1,16,0v56H208V144a8,8,0,0,1,16,0Zm-101.66,5.66a8,8,0,0,0,11.32,0l40-40a8,8,0,0,0-11.32-11.32L136,124.69V32a8,8,0,0,0-16,0v92.69L93.66,98.34a8,8,0,0,0-11.32,11.32Z"/></svg><span class="hcp-tab__label">This app is free to keep</span></span></button>
36277
36359
  <button type="button" class="hcp-x" data-hcp="dismiss" aria-label="Hide this for good"><svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor" aria-hidden="true"><path d="M1.4 0 6 4.6 10.6 0 12 1.4 7.4 6 12 10.6 10.6 12 6 7.4 1.4 12 0 10.6 4.6 6 0 1.4z"/></svg></button>
36278
36360
  </div>
36279
36361
  </aside>`;
@@ -36284,166 +36366,34 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36284
36366
  var INTRO_CSS;
36285
36367
  var init_intro_style = __esm({
36286
36368
  "src/plugins/visitor-drafts/intro-style.js"() {
36287
- INTRO_CSS = `.clay-intro, .clay-about {
36288
- --hcp-ground: #FDF8F0;
36289
- --hcp-surface: #FFFCF6;
36290
- --hcp-sunk: #F4ECDF;
36291
- --hcp-ink: #2B241B;
36292
- --hcp-ink-2: #4A4033;
36293
- --hcp-muted: #6B5942;
36294
- --hcp-line: #E8DCC6;
36295
- --hcp-line-2: #D8C8AF;
36296
- --hcp-brass: #8F6310;
36297
- --hcp-brass-soft: #F0E4CC;
36298
- --hcp-face: #F1E7D4;
36299
- --hcp-edge-hi: #FFF9ED;
36300
- --hcp-edge-lo: #D6C3A5;
36301
- --hcp-shadow: 0 1px 2px rgba(23, 28, 36, .06), 0 14px 34px -14px rgba(43, 36, 27, .32);
36302
- --hcp-sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
36303
- --hcp-serif: Newsreader, Georgia, "Times New Roman", serif;
36304
- --hcp-mono: "IBM Plex Mono", ui-monospace, Menlo, monospace;
36305
- color-scheme: light;
36306
- }
36307
- @media (prefers-color-scheme: dark) {
36308
- .clay-intro, .clay-about {
36309
- --hcp-ground: #0B0C13; --hcp-surface: #11131E; --hcp-sunk: #1A1D2C;
36310
- --hcp-ink: #ECEAF2; --hcp-ink-2: #C9CDE0; --hcp-muted: #8A90AB;
36311
- --hcp-line: #262B42; --hcp-line-2: #353B52;
36312
- --hcp-brass: #D9A445; --hcp-brass-soft: #3A2F17;
36313
- --hcp-face: #22273E; --hcp-edge-hi: #3C4260; --hcp-edge-lo: #1B2033;
36314
- --hcp-shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 16px 38px -14px rgba(0, 0, 0, .7);
36315
- color-scheme: dark;
36316
- }
36317
- }
36318
-
36319
- html:has(> body > .clay-intro), body:has(> .clay-intro) { height: auto !important; min-height: 100%; overflow-y: auto !important; }
36320
-
36321
- .clay-intro, .clay-intro *, .clay-intro *::before, .clay-intro *::after,
36322
- .clay-about, .clay-about *::before, .clay-about *::after {
36323
- box-sizing: border-box; margin: 0; padding: 0; border: 0;
36324
- font: inherit; letter-spacing: normal; text-transform: none; text-shadow: none;
36325
- line-height: inherit; color: inherit; background: none; float: none; max-width: none;
36326
- }
36369
+ INTRO_CSS = `html:has(> body > .clay-intro) { height: auto !important; overflow-y: auto !important; }
36370
+ body:has(> .clay-intro) { height: auto !important; overflow: visible !important; }
36327
36371
  .clay-intro {
36328
- position: relative; z-index: 1; display: block;
36329
- min-height: 100svh;
36330
- background: var(--hcp-ground);
36331
- font-family: var(--hcp-sans); font-size: 16px; font-weight: 400; line-height: 1.5;
36332
- color: var(--hcp-ink); text-align: left;
36333
- -webkit-font-smoothing: antialiased;
36334
- }
36335
- .clay-intro__inner {
36336
- display: flex; flex-direction: column; gap: 18px;
36337
- width: 100%; max-width: 720px; min-height: 100svh; margin: 0 auto;
36338
- padding: max(24px, 6vh) 16px 32px;
36339
- }
36340
- .clay-intro .clay-intro__kicker {
36341
- font-family: var(--hcp-mono); font-size: 11px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase;
36342
- color: var(--hcp-brass);
36343
- }
36344
- .clay-intro__name {
36345
- font-family: var(--hcp-serif); font-size: clamp(30px, 7vw, 44px); font-weight: 500; line-height: 1.12;
36346
- color: var(--hcp-ink); font-variation-settings: "opsz" 48;
36347
- }
36348
- .clay-intro__inner > p { font-size: 18px; line-height: 1.55; color: var(--hcp-ink-2); }
36349
- .clay-intro__inner > a { color: var(--hcp-brass); text-decoration: underline; text-underline-offset: 2px; }
36350
- .clay-intro__inner > video, .clay-intro__inner > img {
36351
- display: block; width: 100%; height: auto; aspect-ratio: 16 / 9;
36352
- background: var(--hcp-sunk); border: 1px solid var(--hcp-line);
36353
- }
36354
- .clay-intro__inner > ul, .clay-intro__inner > ol { padding-left: 22px; font-size: 18px; line-height: 1.55; color: var(--hcp-ink-2); }
36355
- .clay-intro__inner > ul { list-style: disc; }
36356
- .clay-intro__inner > ol { list-style: decimal; }
36357
-
36358
- .clay-intro__actions { display: flex; flex-direction: column; gap: 14px; align-items: stretch; }
36359
- .clay-intro__download {
36360
- align-self: flex-start;
36361
- display: inline-flex; align-items: center; justify-content: center; gap: 8px;
36362
- min-height: 44px; padding: 0 18px;
36363
- font-family: var(--hcp-sans); font-size: 15px; font-weight: 500; line-height: 1.5;
36364
- white-space: nowrap; text-decoration: none; cursor: pointer; user-select: none;
36365
- color: var(--hcp-ground); background: var(--hcp-ink);
36366
- border: 2px solid;
36367
- border-color: color-mix(in srgb, var(--hcp-ink), white 24%) color-mix(in srgb, var(--hcp-ink), black 32%) color-mix(in srgb, var(--hcp-ink), black 32%) color-mix(in srgb, var(--hcp-ink), white 24%);
36368
- transition: background .2s ease;
36369
- }
36370
- .clay-intro__download:hover { background: color-mix(in srgb, var(--hcp-ink), var(--hcp-ground) 12%); }
36371
-
36372
- .clay-intro__signup {
36373
- display: flex; flex-direction: column; gap: 9px;
36374
- padding: 14px 16px;
36375
- background: var(--hcp-surface); border: 1px solid var(--hcp-line); border-left: 3px solid var(--hcp-brass);
36376
- }
36377
- .clay-intro__signup label { font-size: 14px; line-height: 1.45; color: var(--hcp-ink-2); }
36378
- .clay-intro__row { display: flex; gap: 8px; }
36379
- .clay-intro__row input {
36380
- flex: 1 1 auto; min-width: 0; height: 40px; padding: 0 10px;
36381
- font-family: var(--hcp-sans); font-size: 15px; color: var(--hcp-ink);
36382
- background: var(--hcp-ground); border: 1px solid var(--hcp-line-2);
36383
- }
36384
- .clay-intro__row input::placeholder { color: var(--hcp-muted); }
36385
- .clay-intro__row button {
36386
- flex: none; height: 40px; padding: 0 14px;
36387
- font-family: var(--hcp-sans); font-size: 14px; font-weight: 500;
36388
- color: var(--hcp-ink); background: var(--hcp-face); cursor: pointer;
36389
- border: 2px solid; border-color: var(--hcp-edge-hi) var(--hcp-edge-lo) var(--hcp-edge-lo) var(--hcp-edge-hi);
36390
- }
36391
- .clay-intro__row button:hover { background: color-mix(in srgb, var(--hcp-face), var(--hcp-edge-hi) 45%); }
36392
- .clay-intro__hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
36393
- .clay-intro__msg { font-size: 14px; line-height: 1.5; color: var(--hcp-ink-2); }
36394
- .clay-intro__msg[hidden] { display: none; }
36395
- .clay-intro__row[hidden] { display: none; }
36396
-
36397
- .clay-intro__start {
36398
- margin-top: auto;
36399
- display: inline-flex; align-items: center; justify-content: center; gap: 10px;
36400
- width: 100%; min-height: 56px; padding: 0 20px;
36401
- font-family: var(--hcp-sans); font-size: 16px; font-weight: 500;
36402
- color: var(--hcp-ground); background: var(--hcp-ink); cursor: pointer;
36403
- border: 2px solid;
36404
- border-color: color-mix(in srgb, var(--hcp-ink), white 24%) color-mix(in srgb, var(--hcp-ink), black 32%) color-mix(in srgb, var(--hcp-ink), black 32%) color-mix(in srgb, var(--hcp-ink), white 24%);
36405
- transition: background .2s ease;
36406
- }
36407
- .clay-intro__start::after { content: "\\2193"; font-size: 15px; line-height: 1; }
36408
- .clay-intro__start:hover { background: color-mix(in srgb, var(--hcp-ink), var(--hcp-ground) 12%); }
36409
- .clay-intro__download:focus-visible, .clay-intro__start:focus-visible,
36410
- .clay-intro__row button:focus-visible, .clay-intro__row input:focus-visible,
36411
- .clay-about:focus-visible { outline: 2px solid var(--hcp-brass); outline-offset: 2px; }
36412
-
36413
- .clay-about {
36414
- position: fixed; top: 12px; right: 12px; z-index: 2147482000;
36415
- display: inline-flex; align-items: center; justify-content: center; gap: 7px;
36416
- height: 34px; padding: 0 12px;
36417
- font-family: var(--hcp-sans); font-size: 13px; font-weight: 500; line-height: 1.5;
36418
- white-space: nowrap; cursor: pointer; user-select: none;
36419
- color: var(--hcp-ink); background: var(--hcp-face);
36420
- border: 2px solid; border-color: var(--hcp-edge-hi) var(--hcp-edge-lo) var(--hcp-edge-lo) var(--hcp-edge-hi);
36421
- box-shadow: var(--hcp-shadow);
36422
- transition: background .2s ease;
36423
- }
36424
- .clay-about:hover { background: color-mix(in srgb, var(--hcp-face), var(--hcp-edge-hi) 45%); }
36425
-
36426
- @media (min-width: 560px) {
36427
- .clay-intro__actions { flex-direction: row; flex-wrap: wrap; align-items: center; }
36428
- .clay-intro__signup { flex: 1 1 320px; max-width: 520px; }
36429
- }
36430
- @media (pointer: coarse) {
36431
- .clay-intro__download, .clay-intro__start, .clay-intro__row input, .clay-intro__row button { min-height: 44px; }
36432
- .clay-about { min-height: 44px; }
36433
- }
36434
- @media (prefers-reduced-motion: reduce) {
36435
- .clay-intro, .clay-intro *, .clay-about { transition: none; animation: none; }
36372
+ position: relative;
36373
+ display: block;
36436
36374
  }
36437
- @media (forced-colors: active) {
36438
- .clay-intro__download, .clay-intro__start, .clay-intro__row button, .clay-about { border: 1px solid ButtonText; }
36439
- .clay-intro__signup { border: 1px solid CanvasText; }
36375
+ .clay-intro__close {
36376
+ position: absolute; top: 10px; right: 10px; z-index: 1;
36377
+ display: inline-flex; align-items: center; justify-content: center;
36378
+ width: 28px; height: 28px; min-height: 0; margin: 0; padding: 0;
36379
+ border: 0; border-radius: 4px; background: none; box-shadow: none;
36380
+ color: inherit; opacity: .55; cursor: pointer; line-height: 1;
36440
36381
  }
36441
- @media print { .clay-intro, .clay-about { display: none; } }
36382
+ .clay-intro .clay-intro__close:hover { opacity: 1; background: none; color: inherit; }
36383
+ .clay-intro__close:focus-visible { opacity: 1; outline: 2px solid currentColor; outline-offset: 2px; }
36384
+ .clay-intro__close svg { display: block; width: 12px; height: 12px; fill: currentColor; stroke: none; }
36385
+ @media (pointer: coarse) { .clay-intro__close { width: 44px; height: 44px; top: 4px; right: 4px; } }
36386
+ @media print { .clay-intro { display: none; } }
36442
36387
  `;
36443
36388
  }
36444
36389
  });
36445
36390
 
36446
36391
  // src/plugins/visitor-drafts/intro.js
36392
+ function isTextEntry(el5) {
36393
+ if (el5.isContentEditable || el5.closest(TEXT_ENTRY)) return true;
36394
+ if (el5.tagName !== "INPUT") return false;
36395
+ return NON_TEXT_INPUT.indexOf(el5.type) < 0;
36396
+ }
36447
36397
  function forced() {
36448
36398
  try {
36449
36399
  return new URLSearchParams(window.location.search).get("intro") === "1";
@@ -36461,191 +36411,89 @@ html:has(> body > .clay-intro), body:has(> .clay-intro) { height: auto !importan
36461
36411
  }
36462
36412
  function focusApp() {
36463
36413
  const next = [...document.querySelectorAll(FOCUSABLE2)].find(
36464
- (el5) => !el5.disabled && !el5.closest("[clay~='editor-ui']") && (typeof el5.checkVisibility !== "function" || el5.checkVisibility())
36414
+ (el5) => !el5.disabled && !isTextEntry(el5) && !el5.closest("[clay~='editor-ui']") && (typeof el5.checkVisibility !== "function" || el5.checkVisibility())
36465
36415
  );
36466
- if (next) next.focus();
36467
- else document.body.focus();
36468
- }
36469
- function mountIntro({ memory, template, appName, link: link2, tag, source: source3, hadDraft, prompt, snapshot }) {
36470
- if (!template) return null;
36471
- const opts = { memory, template, appName, link: link2, tag, source: source3, hadDraft, prompt, snapshot };
36472
- if (forced()) return mount(opts);
36473
- if (memory.get().intro.done || hadDraft) return mountAbout(opts);
36474
- if (window.location.hash) return null;
36475
- if (window.matchMedia && window.matchMedia("print").matches) return null;
36476
- return mount(opts);
36477
- }
36478
- function mountAbout(opts) {
36479
- stylesOnce();
36480
- const button2 = document.createElement("button");
36481
- button2.type = "button";
36482
- button2.className = "clay-about";
36483
- button2.setAttribute("clay", "editor-ui");
36484
- button2.setAttribute("sap-ignore", "");
36485
- button2.textContent = COPY.about;
36486
- button2.addEventListener("click", () => {
36487
- button2.remove();
36488
- mount({ ...opts, fromAbout: true });
36489
- });
36490
- document.body.appendChild(button2);
36491
- return button2;
36416
+ if (next) next.focus({ preventScroll: true });
36417
+ else document.body.focus({ preventScroll: true });
36492
36418
  }
36493
- function mount(opts) {
36494
- const { memory, template, appName, link: link2, tag, source: source3, prompt, snapshot, fromAbout } = opts;
36419
+ function mountIntro({ memory, template, appName, hadDraft }) {
36420
+ if (!template || !template.content.textContent.trim() && !template.content.querySelector("img, svg, video, canvas")) return null;
36421
+ if (!forced()) {
36422
+ if (memory.get().intro.done || hadDraft) return null;
36423
+ if (window.location.hash) return null;
36424
+ if (window.matchMedia && window.matchMedia("print").matches) return null;
36425
+ }
36426
+ return mount({ memory, template, appName });
36427
+ }
36428
+ function mount({ memory, template, appName }) {
36495
36429
  stylesOnce();
36496
36430
  const section = document.createElement("section");
36497
36431
  section.className = "clay-intro";
36498
36432
  section.setAttribute("clay", "editor-ui");
36499
36433
  section.setAttribute("sap-ignore", "");
36500
36434
  section.setAttribute("aria-label", COPY.label(appName));
36501
- const inner = document.createElement("div");
36502
- inner.className = "clay-intro__inner";
36503
- const kicker = document.createElement("p");
36504
- kicker.className = "clay-intro__kicker";
36505
- kicker.textContent = COPY.kicker;
36506
- const name = document.createElement("h1");
36507
- name.className = "clay-intro__name";
36508
- name.textContent = appName;
36509
- const actions = document.createElement("div");
36510
- actions.className = "clay-intro__actions";
36511
- const download = document.createElement("a");
36512
- download.className = "clay-intro__download";
36513
- download.href = link2;
36514
- download.textContent = COPY.download;
36515
- const form = document.createElement("form");
36516
- form.className = "clay-intro__signup";
36517
- form.noValidate = true;
36518
- const label = document.createElement("label");
36519
- label.setAttribute("for", "clay-intro-email");
36520
- label.textContent = COPY.signupLabel;
36521
- const row = document.createElement("div");
36522
- row.className = "clay-intro__row";
36523
- const email = document.createElement("input");
36524
- email.id = "clay-intro-email";
36525
- email.type = "email";
36526
- email.autocomplete = "email";
36527
- email.required = true;
36528
- email.placeholder = COPY.emailPlaceholder;
36529
- const send3 = document.createElement("button");
36530
- send3.type = "submit";
36531
- send3.textContent = COPY.signup;
36532
- row.append(email, send3);
36533
- const honey = document.createElement("input");
36534
- honey.className = "clay-intro__hp";
36535
- honey.name = "website";
36536
- honey.tabIndex = -1;
36537
- honey.autocomplete = "off";
36538
- honey.setAttribute("aria-hidden", "true");
36539
- const message = document.createElement("p");
36540
- message.className = "clay-intro__msg";
36541
- message.setAttribute("role", "status");
36542
- message.hidden = true;
36543
- form.append(label, row, honey, message);
36544
- actions.append(download, form);
36545
- const start2 = document.createElement("button");
36546
- start2.type = "button";
36547
- start2.className = "clay-intro__start";
36548
- start2.textContent = COPY.start(appName);
36549
- inner.append(kicker, name, template.content.cloneNode(true), actions, start2);
36550
- section.appendChild(inner);
36551
- let observer2 = null;
36435
+ section.appendChild(template.content.cloneNode(true));
36436
+ const close = document.createElement("button");
36437
+ close.type = "button";
36438
+ close.className = "clay-intro__close";
36439
+ close.setAttribute("aria-label", COPY.close);
36440
+ close.innerHTML = '<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor" aria-hidden="true"><path d="M1.4 0 6 4.6 10.6 0 12 1.4 7.4 6 12 10.6 10.6 12 6 7.4 1.4 12 0 10.6 4.6 6 0 1.4z"/></svg>';
36441
+ section.appendChild(close);
36552
36442
  let gone = false;
36553
- function stop2() {
36554
- document.removeEventListener("input", onUse, true);
36555
- document.removeEventListener("change", onUse, true);
36556
- document.removeEventListener("clay:dirty", onUse, true);
36557
- if (observer2) {
36558
- observer2.disconnect();
36559
- observer2 = null;
36560
- }
36561
- if (prompt) prompt.hideForIntro(false);
36562
- }
36563
- function dismiss3(reason, target) {
36443
+ let frame = 0;
36444
+ function dismiss3(reason) {
36564
36445
  if (gone) return;
36565
36446
  gone = true;
36566
- const anchor = target && target.getBoundingClientRect ? target : document.activeElement;
36567
- const before = anchor && anchor.getBoundingClientRect ? anchor.getBoundingClientRect().top : 0;
36447
+ removeEventListener("scroll", onScroll);
36448
+ if (frame) cancelAnimationFrame(frame);
36449
+ const height = section.getBoundingClientRect().height;
36450
+ const before = window.scrollY;
36568
36451
  memory.get().intro.done = reason;
36569
36452
  memory.save();
36570
- stop2();
36571
36453
  section.remove();
36572
- if (reason === "button") {
36573
- window.scrollTo({ top: 0 });
36574
- focusApp();
36575
- } else if (anchor && anchor.getBoundingClientRect) {
36576
- window.scrollBy(0, anchor.getBoundingClientRect().top - before);
36454
+ if (reason === "scrolled") {
36455
+ const locked = /hidden|clip/.test(getComputedStyle(document.body).overflowY + getComputedStyle(document.documentElement).overflowY);
36456
+ window.scrollTo(0, locked ? 0 : Math.max(0, before - height));
36577
36457
  }
36578
- if (fromAbout) mountAbout(opts);
36458
+ announceBottomUi();
36459
+ if (reason !== "scrolled") focusApp();
36579
36460
  }
36580
- function unchanged() {
36581
- return !snapshot || snapshot() === baseline;
36461
+ function onScroll() {
36462
+ if (frame) return;
36463
+ frame = requestAnimationFrame(() => {
36464
+ frame = 0;
36465
+ const bottom = section.getBoundingClientRect().bottom;
36466
+ const atEnd = scrollY > 0 && scrollY + innerHeight >= document.documentElement.scrollHeight - 1;
36467
+ if (bottom < 1 || atEnd && bottom < innerHeight) dismiss3("scrolled");
36468
+ });
36582
36469
  }
36583
- function onUse(event) {
36584
- if (section.contains(event.target)) return;
36585
- if (event.type === "clay:dirty") {
36586
- if (!unchanged()) dismiss3("use", event.target);
36470
+ section.addEventListener("click", (event) => {
36471
+ if (event.target.closest(".clay-intro__close, [visitor-intro-dismiss]")) {
36472
+ dismiss3("closed");
36587
36473
  return;
36588
36474
  }
36589
- if (!unchanged() || event.target?.closest?.("[persist]")) {
36590
- dismiss3("use", event.target);
36591
- return;
36475
+ if (event.target.closest("[visitor-intro-start]")) {
36476
+ event.preventDefault();
36477
+ window.scrollTo({ top: window.scrollY + section.getBoundingClientRect().bottom, behavior: "smooth" });
36592
36478
  }
36593
- const target = event.target;
36594
- setTimeout(() => {
36595
- if (!gone && !unchanged()) dismiss3("use", target);
36596
- }, 0);
36597
- }
36598
- form.addEventListener("submit", (event) => {
36599
- event.preventDefault();
36600
- fetch("/_/newsletter/subscribe", {
36601
- method: "POST",
36602
- headers: { "Content-Type": "application/json" },
36603
- credentials: "same-origin",
36604
- body: JSON.stringify({ email: email.value.trim(), tags: [tag], source: source3, website: honey.value })
36605
- }).then((response) => {
36606
- if (!response.ok) throw new Error("signup failed");
36607
- row.hidden = true;
36608
- message.textContent = COPY.signupThanks;
36609
- message.hidden = false;
36610
- }).catch(() => {
36611
- message.textContent = COPY.signupFailed;
36612
- message.hidden = false;
36613
- });
36614
36479
  });
36615
- start2.addEventListener("click", () => dismiss3("button"));
36616
- const baseline = snapshot ? snapshot() : null;
36617
36480
  document.body.prepend(section);
36618
- document.addEventListener("input", onUse, true);
36619
- document.addEventListener("change", onUse, true);
36620
- document.addEventListener("clay:dirty", onUse, true);
36621
- if (prompt) {
36622
- prompt.hideForIntro(true);
36623
- if (typeof IntersectionObserver === "function") {
36624
- observer2 = new IntersectionObserver((entries3) => {
36625
- for (const entry of entries3) prompt.hideForIntro(entry.intersectionRatio > 0.3);
36626
- });
36627
- observer2.observe(section);
36628
- }
36629
- }
36481
+ announceBottomUi();
36482
+ addEventListener("scroll", onScroll, { passive: true });
36630
36483
  return section;
36631
36484
  }
36632
- var COPY, FOCUSABLE2;
36485
+ var COPY, FOCUSABLE2, TEXT_ENTRY, NON_TEXT_INPUT;
36633
36486
  var init_intro = __esm({
36634
36487
  "src/plugins/visitor-drafts/intro.js"() {
36635
36488
  init_intro_style();
36489
+ init_bottom_ui();
36636
36490
  COPY = {
36637
- kicker: "Free app",
36638
- download: "Download free",
36639
- signupLabel: "I make one of these about every two weeks. Get the next one by email.",
36640
- emailPlaceholder: "you@example.com",
36641
- signup: "Send me the next one",
36642
- signupThanks: "Thanks. Check your email for a link to confirm.",
36643
- signupFailed: "That didn't go through. Check the address and try again.",
36644
- start: (appName) => `Start using ${appName}`,
36645
- about: "About this app",
36491
+ close: "Hide this introduction",
36646
36492
  label: (appName) => `About ${appName}`
36647
36493
  };
36648
36494
  FOCUSABLE2 = "a[href], button, input, select, textarea, [tabindex]:not([tabindex='-1'])";
36495
+ TEXT_ENTRY = "textarea, select";
36496
+ NON_TEXT_INPUT = ["checkbox", "radio", "button", "submit", "reset", "file"];
36649
36497
  }
36650
36498
  });
36651
36499
 
@@ -36689,36 +36537,54 @@ html:has(> body > .clay-intro), body:has(> .clay-intro) { height: auto !importan
36689
36537
  close.addEventListener("click", () => {
36690
36538
  chip2.remove();
36691
36539
  liftOff();
36540
+ release();
36692
36541
  });
36693
36542
  chip2.append(lead, action2, close);
36694
36543
  document.body.appendChild(chip2);
36544
+ const vars = document.createElement("style");
36545
+ vars.id = "clay-owner-vars";
36546
+ vars.setAttribute("clay", "editor-ui");
36547
+ document.head.appendChild(vars);
36548
+ let published = "";
36549
+ function publish(lift2) {
36550
+ const next = `:root { --clay-owner-room: ${Math.ceil(chip2.getBoundingClientRect().height) + 16}px; }`;
36551
+ if (vars.textContent !== next) vars.textContent = next;
36552
+ if (published === next + lift2) return;
36553
+ published = next + lift2;
36554
+ announceBottomUi();
36555
+ }
36556
+ function release() {
36557
+ vars.remove();
36558
+ announceBottomUi();
36559
+ }
36695
36560
  let frame = 0;
36696
36561
  function lift() {
36697
36562
  if (frame) return;
36698
36563
  frame = requestAnimationFrame(() => {
36699
36564
  frame = 0;
36700
- const y2 = window.innerHeight - 3;
36701
- let raise = 0;
36702
- const hits = document.elementsFromPoint ? document.elementsFromPoint(24, y2) : [];
36703
- for (const hit of hits) {
36704
- for (let el5 = hit; el5 && el5 !== document.body && el5 !== document.documentElement; el5 = el5.parentElement) {
36705
- if (chip2.contains(el5)) break;
36706
- const position = getComputedStyle(el5).position;
36707
- if (position === "fixed" || position === "sticky") {
36708
- raise = Math.max(raise, Math.ceil(window.innerHeight - el5.getBoundingClientRect().top));
36709
- break;
36710
- }
36711
- }
36712
- }
36713
- chip2.style.setProperty("--hcp-lift", (raise > 0 && raise < window.innerHeight / 3 ? raise : 0) + "px");
36565
+ let lift2 = bottomBarHeight(24, (el5) => chip2.contains(el5) || el5.closest("#hcp"));
36566
+ const panel2 = promptPanel(chip2.getBoundingClientRect());
36567
+ const covered = panel2 >= window.innerHeight / 3;
36568
+ if (panel2 && !covered) lift2 = Math.max(lift2, panel2 - 4);
36569
+ chip2.style.visibility = covered ? "hidden" : "";
36570
+ chip2.style.setProperty("--hcp-lift", lift2 + "px");
36571
+ publish(covered ? -1 : lift2);
36714
36572
  });
36715
36573
  }
36716
36574
  function liftOff() {
36717
36575
  removeEventListener("scroll", lift);
36718
36576
  removeEventListener("resize", lift);
36577
+ document.removeEventListener(BOTTOM_UI_CHANGED, lift);
36578
+ document.removeEventListener("transitionend", lift, true);
36579
+ document.removeEventListener("pointerup", lift, true);
36580
+ window.removeEventListener("hashchange", lift);
36719
36581
  }
36720
36582
  addEventListener("scroll", lift, { passive: true });
36721
36583
  addEventListener("resize", lift);
36584
+ document.addEventListener(BOTTOM_UI_CHANGED, lift);
36585
+ document.addEventListener("transitionend", lift, true);
36586
+ document.addEventListener("pointerup", lift, true);
36587
+ window.addEventListener("hashchange", lift);
36722
36588
  lift();
36723
36589
  return chip2;
36724
36590
  }
@@ -36726,6 +36592,7 @@ html:has(> body > .clay-intro), body:has(> .clay-intro) { height: auto !importan
36726
36592
  var init_owner_chip = __esm({
36727
36593
  "src/plugins/visitor-drafts/owner-chip.js"() {
36728
36594
  init_is_edit_mode();
36595
+ init_bottom_ui();
36729
36596
  COPY2 = {
36730
36597
  draft: "You're seeing a private draft, like a visitor.",
36731
36598
  draftAction: "Edit the original",
@@ -36775,17 +36642,23 @@ html:has(> body > .clay-intro), body:has(> .clay-intro) { height: auto !importan
36775
36642
  -webkit-font-smoothing: antialiased;
36776
36643
  }
36777
36644
  .clay-owner__action {
36778
- flex: none; font-weight: 600; color: var(--hcp-brass); cursor: pointer;
36645
+ flex: none; min-height: 0; font-weight: 600; color: var(--hcp-brass); cursor: pointer;
36779
36646
  text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--hcp-line-2);
36780
36647
  white-space: nowrap;
36781
36648
  }
36782
- .clay-owner__action:hover { color: var(--hcp-ink); }
36649
+ .clay-owner .clay-owner__action:hover { color: var(--hcp-ink); background: none; }
36783
36650
  .clay-owner__x {
36784
36651
  flex: none; display: inline-flex; align-items: center; justify-content: center;
36785
- width: 24px; height: 24px; font-size: 15px; color: var(--hcp-muted); cursor: pointer;
36652
+ width: 24px; height: 24px; min-height: 0; font-size: 15px; color: var(--hcp-muted); cursor: pointer;
36786
36653
  }
36787
- .clay-owner__x:hover { color: var(--hcp-ink); }
36654
+ .clay-owner .clay-owner__x:hover { color: var(--hcp-ink); background: none; }
36788
36655
  .clay-owner__action:focus-visible, .clay-owner__x:focus-visible { outline: 2px solid var(--hcp-brass); outline-offset: 2px; }
36656
+
36657
+ .clay-owner svg {
36658
+ display: block; flex: none; width: 1em; height: 1em; line-height: 1;
36659
+ fill: currentColor; stroke: none; stroke-width: 0; stroke-linecap: butt; stroke-linejoin: miter;
36660
+ }
36661
+ .clay-owner button, .clay-owner a { border-radius: 0; line-height: 1.45; }
36789
36662
  @media (pointer: coarse) {
36790
36663
  .clay-owner__action, .clay-owner__x { min-height: 44px; }
36791
36664
  .clay-owner__x { width: 44px; }
@@ -36862,8 +36735,8 @@ html:has(> body > .clay-intro), body:has(> .clay-intro) { height: auto !importan
36862
36735
  const appName = document.querySelector('meta[name="application-name"]')?.content?.trim() || document.title.split(/:|\s\|\s/)[0].trim() || "This app";
36863
36736
  const template = document.querySelector("template[visitor-intro]");
36864
36737
  const start2 = () => {
36865
- const prompt = mountPrompt({ memory, appName, link: downloadLink });
36866
- mountIntro({ memory, template, appName, link: downloadLink, tag: signupTag(slot, template), source, hadDraft: result2.hadDraft, prompt, snapshot: store.snapshot });
36738
+ const prompt = mountPrompt({ memory, appName, link: downloadLink, tag: signupTag(slot, template), source });
36739
+ mountIntro({ memory, template, appName, hadDraft: result2.hadDraft });
36867
36740
  if (isOwner) mountOwnerChip();
36868
36741
  document.addEventListener("clay:drafts-store-failed", () => prompt.showError());
36869
36742
  document.addEventListener("clay:drafts-saved", () => prompt.clearError());