* {
  box-sizing: border-box;
}

:root {
  --bg: #f4f2ee;
  --ink: #111;
  --surface: #fff;
  --accent-soft: #fff7cf;
  --panel: rgba(255, 255, 255, 0.72);
}

:root.dark {
  --bg: #111;
  --ink: #f4f2ee;
  --surface: #1d1c1a;
  --accent-soft: #45401c;
  --panel: rgba(255, 255, 255, 0.06);
}

body {
  margin: 0;
  background: var(--bg);
  font-family: "Poppins", sans-serif;
  color: var(--ink);
  transition: background 0.25s ease, color 0.25s ease;
}

button {
  font: inherit;
}

/* ---------- Header ---------- */

/* Row, right-aligned — theme toggle and the menu hamburger sit side by
   side as a natural flex group (gap handles their spacing), rather than
   each being independently absolute-positioned with hand-tuned offsets. */
/* Menu on the left, dark-mode toggle on the right — DOM order (menu-wrap
   first) is what actually puts the menu on the left; space-between just
   pushes the two ends of that order apart. */
/* Same max-width + centering as .board-title-wrap/.stack below — without
   this, the header pins to the raw viewport edges while the content stays
   in its narrow centered column, so on wide desktop windows the icons end
   up floating far outside the actual page content instead of framing it. */
.top-bar {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: flex-start;
  max-width: 720px;
  margin: 0 auto;
  padding: 1.2rem 1.25rem;
  position: relative;
}

/* Dark-mode toggle + Share stacked, right side — moved out of the toolbar
   row above the cards so that row is shorter and the cards can sit closer
   to the bio. */
.header-right {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}

/* ---------- Theme (dark mode) toggle ---------- */

/* Hidden on boards with a custom background color (see syncThemeAvailability
   in app.js) — the class's own display:flex below would otherwise silently
   win over the [hidden] attribute's default display:none, since author
   styles beat the UA stylesheet on an equal-specificity tie. */
.theme-toggle[hidden] {
  display: none;
}

.theme-toggle {
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 4px;
  background: var(--surface);
  border: 2px solid var(--ink);
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.2);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.25s ease, border-color 0.25s ease;
  z-index: 60;
}

.theme-toggle:hover {
  transform: translateY(-2px);
  box-shadow: 0 5px 0 rgba(17, 17, 17, 0.25);
}

.theme-toggle:active {
  transform: translateY(1px);
  box-shadow: 0 1px 0 rgba(17, 17, 17, 0.2);
}

.theme-toggle:focus-visible {
  outline: 3px solid #d97b29;
  outline-offset: 3px;
}

.theme-icon {
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: var(--ink);
  opacity: 0.35;
  transition: opacity 0.2s ease, background 0.2s ease, color 0.2s ease;
}

.theme-icon svg {
  display: block;
}

/* sun active in light mode, moon active in dark mode */
.theme-sun {
  opacity: 1;
  background: var(--accent-soft);
}

:root.dark .theme-sun {
  opacity: 0.35;
  background: transparent;
}

:root.dark .theme-moon {
  opacity: 1;
  background: var(--accent-soft);
}

/* Linktree-style templates don't show any app branding or footer at all on
   the actual share page — the user's own content is the whole point. One
   small top-right hamburger tucks away everything that isn't that: app
   branding, "create your own", and link recovery. No separate footer.
   (Full styling, including the .speech-bubble positioning override, lives
   further down right after .speech-bubble.open — same specificity, later
   source order needed to actually win.) */
.menu-wrap {
  position: relative;
}

.hamburger-btn {
  background: var(--surface);
  border: 2px solid var(--ink);
  border-radius: 999px;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform 0.15s ease;
  color: var(--ink);
}

.hamburger-btn:hover {
  transform: translateY(-2px);
}

/* ---------- Board title (user-customizable) ---------- */

.board-title-wrap {
  max-width: 720px;
  margin: 0 auto;
  padding: 0 1rem;
  text-align: center;
}

/* h2-scale "display name" under the avatar, Linktree-style — not the huge
   page-banner h1 this used to be. Uppercase is now the user's choice (see
   .title-caps below) instead of always forced. */
.board-title {
  font-family: var(--title-font, "Archivo Black"), sans-serif;
  font-size: clamp(1.35rem, 5vw, 1.9rem);
  letter-spacing: -0.01em;
  line-height: 1.2;
  margin: 0;
  text-align: center;
  overflow-wrap: anywhere;
}

.board-title.title-caps {
  text-transform: uppercase;
}

/* ---------- Profile image ---------- */

/* Outer wrapper is NOT clipped — the edit button sits on its edge and must
   not be cut off by the circular photo mask (that clipping lives one level
   in, on .profile-image-circle). First thing in <main> now (Linktree-style
   avatar → name → bio → links), so its own top margin is the page's only
   spacing below the header. */
.profile-image {
  position: relative;
  width: 112px;
  height: 112px;
  margin: 1.4rem auto 0.7rem;
}

.profile-image-circle {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  overflow: hidden;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Generic placeholder avatar — shown any time there's no photo yet, in both
   view and edit mode, so first-time visitors see a profile photo is a thing
   this board can have, not just an empty gap. */
.profile-image:not(.has-image) .profile-image-circle {
  background: rgba(17, 17, 17, 0.08);
  color: rgba(17, 17, 17, 0.35);
}

.profile-image.has-image .profile-image-placeholder {
  display: none;
}

/* Dashed ring in edit mode when no photo is set yet — an extra edit-mode cue
   on top of the always-on placeholder fill above. */
body.editing .profile-image:not(.has-image) .profile-image-circle {
  border: 2px dashed rgba(17, 17, 17, 0.3);
}

.profile-image-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.profile-image-btn {
  position: absolute;
  right: -4px;
  bottom: -4px;
  width: 34px;
  height: 34px;
  display: none;
  align-items: center;
  justify-content: center;
  color: #111;
  background: #fff;
  border: 2px solid #111;
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(17, 17, 17, 0.2);
  z-index: 1;
}

.profile-image-btn svg {
  display: block;
}

body.editing .profile-image-btn {
  display: flex;
}

body.editing .board-title {
  display: inline-block;
  max-width: 100%;
  cursor: text;
  outline: none;
  border-bottom: 3px dashed rgba(17, 17, 17, 0.35);
  padding-bottom: 4px;
}

:root.dark body.editing .board-title {
  border-bottom-color: rgba(255, 255, 255, 0.35);
}

body.editing .board-title::after {
  content: " ✎";
  font-size: 0.45em;
  opacity: 0.4;
}

body.editing .board-title:focus {
  border-bottom-color: #d97b29;
}

body.editing .board-title:focus::after {
  content: "";
}

/* Title/bio color+font+caps controls — one shared "identity block" style
   for both, sitting below the bio (not the title) since it styles both.
   Same look as the card buttons, shown in edit mode only. */
.title-controls {
  display: none;
  justify-content: center;
  gap: 0.5rem;
  margin: 0.2rem auto 0.9rem;
  padding: 0 1rem;
}

body.editing .title-controls {
  display: flex;
}

.title-btn {
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #111;
  background: #fff;
  border: 2px solid #111;
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(17, 17, 17, 0.2);
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}

.title-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.25);
}

.title-btn:active {
  transform: translateY(1px);
  box-shadow: 0 1px 0 rgba(17, 17, 17, 0.2);
}

.title-color-btn,
.card-text-color-btn {
  background: #f1c40f;
}

.title-font-btn,
.card-font-btn,
.card-border-btn {
  background: #fff;
}

.title-caps-btn {
  background: #fff;
}

.title-caps-btn[aria-pressed="true"] {
  background: var(--accent-soft);
}

.title-color-btn,
.title-font-btn,
.title-caps-btn {
  line-height: 1;
}

.font-icon-mark {
  display: block;
  font-family: var(--title-font, "Archivo Black"), sans-serif;
  font-size: 0.88rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.04em;
}

/* The color/caps buttons' own "Aa" glyphs are icons, not font specimens —
   they shouldn't visually shift face every time the title/bio font
   changes (that's what made the font button's own icon look broken too,
   before it became a fixed SVG glyph instead of live-previewing text). */
.title-controls .font-icon-mark {
  font-family: "Archivo Black", sans-serif;
}

/* ---------- Speech bubble menu ---------- */

.speech-bubble {
  position: absolute;
  top: calc(100% + 18px);
  left: 50%;
  transform: translate(-50%, -8px) scale(0.85);
  transform-origin: top center;
  background: var(--surface);
  border: 2px solid var(--ink);
  border-radius: 20px;
  padding: 1.6rem 1.4rem 0.9rem;
  display: flex;
  flex-direction: row;
  gap: 1.4rem;
  white-space: nowrap;
  box-shadow: 0 6px 0 rgba(17, 17, 17, 0.15);
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
  transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
  z-index: 50;
}

.speech-bubble.open {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transform: translate(-50%, 0) scale(1);
}

/* Anchored to .menu-wrap, not the shared positionBubble() mechanism — this
   button never moves around the page like the per-card pickers do, so a
   plain CSS-relative dropdown is all it needs. .speech-bubble's own
   left/transform above assume horizontal centering under the anchor
   (left:50% + a -50% translate); overridden here since this one
   right-aligns under a corner button instead — same specificity as
   .speech-bubble/.speech-bubble.open (one class each), so this only
   actually wins because it's declared later in the cascade.  */
.site-menu {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.15rem;
  min-width: 160px;
  top: calc(100% + 12px);
  left: 0;
  right: auto;
  padding: 0.25rem 0.9rem 0.6rem;
  transform: translateY(-8px) scale(0.9);
  transform-origin: top left;
}

.site-menu.open {
  transform: translateY(0) scale(1);
}

.site-menu a,
.site-menu button {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-radius: 8px;
  padding: 0.4rem 0.5rem;
  font-family: "Poppins", sans-serif;
  font-size: 0.76rem;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  cursor: pointer;
}

.site-menu a:hover,
.site-menu button:hover {
  background: rgba(217, 123, 41, 0.12);
}

/* Indents the two text items a bit from the edge so they don't feel glued
   to the bubble's corner; .site-menu-stamp is excluded — it's a plain
   centered logo mark, not a text row. */
.site-menu a:not(.site-menu-brand):not(.site-menu-stamp),
.site-menu button {
  padding-left: 1.3rem;
}

.site-menu-brand {
  display: flex !important;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 15%, transparent);
  border-radius: 10px 10px 0 0 !important;
  margin-bottom: 0.2rem;
  padding-top: 0.0rem !important;
  padding-bottom: 0.25rem !important;
}

.site-menu a:not(.site-menu-brand):not(.site-menu-stamp),
.site-menu button {
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 15%, transparent);
  border-radius: 10px 10px 0 0;
  margin-bottom: 0.2rem;
  padding-bottom: 0.5rem;
}


.site-menu-brand-wordmark {
  font-family: "Nunito Sans", sans-serif;
  font-weight: 400;
  font-size: 1.3rem;
  letter-spacing: 0.04em;
  color: var(--ink);
}

/* Quiet closing mark, not a menu "line" — no border, no full-width row
   padding, just a small faded stamp confirming this is the Mind Base app.
   ".site-menu a.site-menu-stamp" (class+class+element) outranks the plain
   ".site-menu a" base rule above so these overrides actually stick. */
.site-menu a.site-menu-stamp {
  display: flex;
  justify-content: center;
  width: 100%;
  padding: 0.3rem 0 0.05rem;
}

.site-menu-stamp img {
  height: 13px;
  width: auto;
  object-fit: contain;
  opacity: 0.55;
}

.site-menu-stamp:hover img {
  opacity: 0.85;
}

/* No more pointer/tail aimed at the anchor button (removed — it never
   reliably pointed the right way once bubbles could open above their
   anchor too), so every bubble gets an explicit close affordance instead. */
.speech-bubble-close {
  position: absolute;
  top: 0.45rem;
  right: 0.45rem;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-family: "Archivo Black", sans-serif;
  font-size: 0.6rem;
  line-height: 1;
  color: var(--ink);
  background: var(--surface);
  border: 2px solid var(--ink);
  border-radius: 999px;
  cursor: pointer;
}

.speech-bubble-close:hover {
  opacity: 0.8;
}

/* :not(.site-menu) — the hamburger dropdown reuses .speech-bubble for its
   shared popup look/position, but has its own complete link styling above;
   without this exclusion, this rule ties in specificity with .site-menu a
   and (being declared later) silently wins on font-size/weight/padding. */
.speech-bubble:not(.site-menu) a {
  text-decoration: none;
  color: var(--ink);
  font-weight: 700;
  font-size: 0.95rem;
  padding: 0.3rem 0;
  border-bottom: 2px solid transparent;
  transition: border-color 0.15s ease;
}

.speech-bubble:not(.site-menu) a:hover {
  border-color: #d97b29;
}

/* ---------- Font picker bubble ---------- */

/* Reuses the speech-bubble look, but positioned in page coordinates next to
   whichever F button opened it (app.js sets left/top inline). */
.speech-bubble.font-bubble {
  /* Real position is set inline by app.js the first time a font picker
     opens. Until then, top/left:auto would fall back to this element's
     static position — the very end of <body> — stretching the whole page's
     scroll height by the bubble's own height even while invisible. 0/0
     keeps it harmless (it's hidden anyway) until JS repositions it. */
  top: 0;
  left: 0;
  flex-direction: column;
  align-items: stretch;
  gap: 0.3rem;
  padding: 1.5rem 0.9rem 0.7rem;
  transform: translateY(-8px) scale(0.92);
}

/* Only the actual font list is long enough to scroll — kept in its own
   inner box so fontBubble itself (and its close button) doesn't scroll. */
.font-options-list {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  max-height: min(60vh, 195px); /* ~5 font options before it scrolls */
  overflow-y: auto;
}

.speech-bubble.font-bubble.open {
  transform: translateY(0) scale(1);
}

.speech-bubble.font-bubble.above {
  transform: translateY(8px) scale(0.92);
  transform-origin: bottom center;
}

.speech-bubble.font-bubble.above.open {
  transform: translateY(0) scale(1);
}

/* Each option renders in its own font so people pick by eye */
.font-option {
  background: none;
  border: none;
  color: var(--ink);
  cursor: pointer;
  font-size: 1.05rem;
  line-height: 1.3;
  padding: 0.3rem 0.55rem;
  border-radius: 10px;
  text-align: left;
  white-space: nowrap;
}

.font-option:hover {
  background: rgba(217, 123, 41, 0.18);
}

.font-option.selected {
  background: var(--accent-soft);
}

.theme-option {
  font-family: "Archivo Black", sans-serif;
  font-size: 0.95rem;
}

.speech-bubble.color-bubble {
  width: min(280px, calc(100vw - 16px));
  white-space: normal;
  gap: 0.75rem;
}

.speech-bubble.share-info-bubble {
  width: min(280px, calc(100vw - 16px));
  white-space: normal;
  gap: 0;
  font-family: "Poppins", sans-serif;
  font-size: 0.92rem;
  font-weight: 600;
  line-height: 1.35;
 }

.color-bubble-label {
  font-family: "Archivo Black", sans-serif;
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.7;
}

.color-swatch-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.55rem;
}

.color-swatch {
  width: 100%;
  aspect-ratio: 1;
  border: 2px solid var(--ink);
  border-radius: 14px;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(17, 17, 17, 0.16);
  transition: transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
}

.color-swatch:hover {
  transform: translateY(-1px);
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.2);
}

.color-swatch.selected {
  border-color: #d97b29;
  box-shadow: 0 0 0 2px rgba(217, 123, 41, 0.18);
}

.color-custom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  font-family: "Poppins", sans-serif;
  font-size: 0.85rem;
  font-weight: 700;
}

.color-custom-input {
  width: 52px;
  height: 38px;
  border: 2px solid var(--ink);
  border-radius: 12px;
  background: none;
  padding: 0;
  cursor: pointer;
  flex: 0 0 auto;
}

.color-custom-input::-webkit-color-swatch-wrapper {
  padding: 0;
}

.color-custom-input::-webkit-color-swatch,
.color-custom-input::-moz-color-swatch {
  border: none;
  border-radius: 10px;
}

/* Border-thickness section — only present in the bubble's layout when
   opened for the card-border button (see openColorPicker's widthOptions
   param); every other use (title/bg/text color) never shows this at all. */
.color-width-section {
  display: none;
}

.speech-bubble.color-bubble.has-width-options .color-width-section {
  display: block;
}

.color-width-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.55rem;
  margin-top: 0.4rem;
}

.color-width-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  padding: 0.55rem 0.3rem;
  border: 2px solid var(--ink);
  border-radius: 14px;
  background: var(--surface);
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(17, 17, 17, 0.16);
  transition: transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
}

.color-width-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.2);
}

.color-width-btn.selected {
  border-color: #d97b29;
  box-shadow: 0 0 0 2px rgba(217, 123, 41, 0.18);
}

.color-width-preview {
  width: 28px;
  border-radius: 999px;
  background: var(--ink);
}

.color-width-value {
  font-family: "Poppins", sans-serif;
  font-size: 0.68rem;
  font-weight: 700;
  opacity: 0.7;
}

/* ---------- Custom link slug ---------- */

.slug-field {
  max-width: 340px;
  width: 100%;
  margin: 0.7rem auto 1.4rem;
  padding: 0 1.25rem;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Only matters before a board has a home — owner-mode boards already have
   their id, and shared-view visitors aren't the board's owner. */
body.owner-mode .slug-field,
body.shared-view .slug-field {
  display: none;
}

/* Fixed white chip, not theme-variable — the page background can be any
   color the owner picks, so this needs its own guaranteed-contrast
   backdrop rather than relying on --ink/--surface to stay legible. */
.slug-field-prefix {
  display: inline-block;
  background: #fff;
  color: #111;
  border: 1.5px solid rgba(17, 17, 17, 0.15);
  white-space: nowrap;
  font-size: 0.85rem;
  font-weight: 700;
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  margin-bottom: 0.4rem;
}

#slugInput {
  width: 100%;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--surface);
  font-family: inherit;
  /* Same iOS zoom-on-focus threshold as the recover-modal input — this
     gets tapped directly by users typing their slug. */
  font-size: 16px;
  font-weight: 700;
  color: var(--ink);
  padding: 0.4rem 0.7rem;
  text-align: center;
  transition: border-color 0.15s ease;
}

#slugInput:focus {
  outline: none;
  border-color: #d97b29;
}

.slug-field.has-error #slugInput {
  border-color: #d02b2b;
}

.slug-field-error {
  display: none;
  margin-top: 0.4rem;
  color: #d02b2b;
  font-size: 0.78rem;
  font-weight: 600;
  text-align: center;
}

.slug-field.has-error .slug-field-error {
  display: block;
}

#slugInput::placeholder {
  color: var(--ink);
  opacity: 0.4;
  font-weight: 600;
}

/* ---------- Edit toggle ---------- */

.stack-toolbar {
  max-width: 720px;
  margin: 1.3rem auto -3rem;
  padding: 0 1.25rem;
  display: flex;
  justify-content: flex-start;
  align-items: center;
  gap: 0.55rem;
  position: relative;
  z-index: 40;
}

.share-btn {
  font-family: "Archivo Black", sans-serif;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  color: #111;
  background: #fff;
  border: 2px solid #111;
  border-radius: 999px;
  padding: 0.45rem 1.1rem;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(17, 17, 17, 0.2);
}

.stack-toolbar > .share-btn:first-of-type {
  margin-left: 0.7rem;
}

.theme-select-btn {
  margin-left: auto !important;
  /* Card presentation theme only matters while actively editing — outside
     edit mode it's just extra chrome on your own board's normal view, and
     whatever theme you had selected when you last saved is what visitors
     see, so there's nothing to change here until you're back in edit mode. */
  display: none;
}

.board-bg-btn {
  margin-left: 0 !important;
}

body.editing .theme-select-btn {
  display: inline-flex;
}

.share-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.25);
}

.share-btn:active {
  transform: translateY(1px);
  box-shadow: 0 1px 0 rgba(17, 17, 17, 0.2);
}

.share-btn:disabled {
  opacity: 0.55;
  cursor: default;
  transform: none;
  box-shadow: 0 2px 0 rgba(17, 17, 17, 0.2);
}

/* Icon-only variant (Save/Share/Theme/Background) — same pill button, just a fixed
   square so the icon centers instead of stretching with text padding. */
.share-btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
}

/* Shared-view: no edit toggle */
body.shared-view .edit-toggle {
  display: none;
}

body.shared-view .theme-select-btn {
  display: none;
}

/* Transient status messages (long link, bad link, etc.) */
#toast {
  position: fixed;
  left: 50%;
  bottom: 1.5rem;
  transform: translateX(-50%) translateY(12px);
  max-width: min(90vw, 420px);
  font-family: "Poppins", sans-serif;
  font-size: 0.85rem;
  font-weight: 700;
  color: #111;
  background: #fff;
  border: 2px solid #111;
  border-radius: 12px;
  padding: 0.7rem 1rem;
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.2);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
  z-index: 100;
}

#toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Add-card / reset actions under the stack, edit mode only */
.stack-actions {
  display: none;
  max-width: 720px;
  margin: -4.5rem auto 4rem;
  padding: 0 1.25rem;
  gap: 0.6rem;
  position: relative;
  z-index: 40;
}

body.editing .stack-actions {
  display: flex;
}

.stack-action-btn {
  font-family: "Archivo Black", sans-serif;
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  color: #111;
  background: #fff;
  border: 2px solid #111;
  border-radius: 999px;
  padding: 0.6rem 1.1rem;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(17, 17, 17, 0.2);
}

.stack-action-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.25);
}

.stack-action-btn:active {
  transform: translateY(1px);
  box-shadow: 0 1px 0 rgba(17, 17, 17, 0.2);
}

.stack-action-danger {
  color: #c0392b;
}

.edit-toggle {
  position: relative;
  display: flex;
  align-items: center;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}

/* Absolutely positioned so it floats above the track instead of adding to
   the button's own height — the toggle stays exactly where it was. */
.edit-toggle-label {
  position: absolute;
  top: -13px;
  left: 50%;
  transform: translateX(-50%);
  font-family: "Archivo Black", sans-serif;
  font-size: 0.55rem;
  letter-spacing: 0.07em;
  color: var(--ink);
  opacity: 0.55;
  white-space: nowrap;
}

.edit-toggle-track {
  display: block;
  position: relative;
  width: 66px;
  height: 36px;
  background: var(--surface);
  border: 2px solid var(--ink);
  border-radius: 999px;
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.2);
  transition: background 0.2s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.edit-toggle-knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 26px;
  height: 26px;
  background: var(--ink);
  border-radius: 50%;
  transition: transform 0.2s ease, background 0.25s ease;
}

.edit-toggle:hover .edit-toggle-track {
  transform: translateY(-2px);
  box-shadow: 0 5px 0 rgba(17, 17, 17, 0.25);
}

.edit-toggle:active .edit-toggle-track {
  transform: translateY(1px);
  box-shadow: 0 1px 0 rgba(17, 17, 17, 0.2);
}

.edit-toggle:focus-visible {
  outline: none;
}

.edit-toggle:focus-visible .edit-toggle-track {
  outline: 3px solid #d97b29;
  outline-offset: 3px;
}

.edit-toggle[aria-pressed="true"] .edit-toggle-track {
  background: var(--accent-soft);
}

.edit-toggle[aria-pressed="true"] .edit-toggle-knob {
  transform: translateX(30px);
}

/* ---------- Card stack ---------- */

.stack {
  max-width: 720px;
  margin: 4rem auto 6rem;
  padding: 0 1.25rem;
  display: flex;
  flex-direction: column;
}

.stack[data-card-theme="minimal"] {
  gap: 0;
}

.card {
  display: block;
  position: relative;
  overflow: hidden;
  text-decoration: none;
  color: var(--card-text-color, #171412);
  font-family: "Anton", sans-serif;
  font-weight: 400;
  font-size: clamp(1.3rem, 3.6vw, 2.1rem);
  letter-spacing: 0.01em;
  min-height: 7.4rem;
  padding: 1.3rem 2.2rem;
  border: 3px solid #111;
  border-radius: 18px;
  margin-top: -1.1rem;
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.06),
    0 10px 20px -6px rgba(0, 0, 0, 0.16);
  transform: rotate(var(--tilt)) translateX(var(--nudge));
  z-index: var(--z);
  transition: transform 0.25s ease, box-shadow 0.15s ease, margin-top 0.25s ease, padding 0.25s ease, border-color 0.25s ease;
  cursor: pointer;
}

.card:first-child {
  margin-top: 0;
}

.stack[data-card-theme="minimal"] .card {
  border: 1px solid #d8d8d8;
  border-radius: 0;
  margin-top: 0;
  box-shadow: none;
  transform: none;
}

.stack[data-card-theme="minimal"] .card + .card {
  margin-top: -1px;
}

.card-title,
.card-tag,
.card-description {
  display: block;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.card-title {
  width: 100%;
  padding-right: 12rem;
  font-family: var(--card-font, "Anton"), sans-serif;
  position: relative;
  z-index: 1;
}

.card-tag {
  display: inline-block;
  max-width: calc(100% - 12rem);
  margin-top: 0.45rem;
  padding: 0.18rem 0.6rem 0.22rem;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-family: var(--card-font, "Anton"), sans-serif;
  font-size: clamp(0.62rem, 1.25vw, 0.76rem);
  letter-spacing: 0.02em;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0.88;
  position: relative;
  z-index: 1;
  vertical-align: top;
}

.card-tag:empty {
  display: none;
}

.card-description {
  position: absolute;
  left: 2.2rem;
  right: 12.4rem;
  top: 50%;
  font-family: var(--card-font, "Anton"), sans-serif;
  font-size: clamp(0.82rem, 1.7vw, 1rem);
  letter-spacing: 0.01em;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0;
  transform: translateY(calc(-50% + 8px));
}

.card-index {
  display: none;
  position: absolute;
  top: 14px;
  right: 18px;
  font-family: "Poppins", sans-serif;
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.05em;
  color: rgba(17, 17, 17, 0.32);
}

.card-open {
  position: absolute;
  top: 50%;
  right: 1.2rem;
  transform: translateY(calc(-50% + 8px));
  opacity: 0;
  pointer-events: none;
  font-family: "Archivo Black", sans-serif;
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  line-height: 1;
  text-decoration: none;
  color: #111;
  background: #fff;
  border: 2px solid #111;
  border-radius: 999px;
  padding: 0.7rem 1.2rem;
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.2);
  transition: opacity 0.2s ease, transform 0.2s ease, box-shadow 0.15s ease;
  z-index: 2;
}

.card-open:hover {
  box-shadow: 0 5px 0 rgba(17, 17, 17, 0.25);
  transform: translateY(calc(-50% - 2px));
}

.card-open:active {
  box-shadow: 0 1px 0 rgba(17, 17, 17, 0.2);
  transform: translateY(calc(-50% + 1px));
}

.card-thumb {
  position: absolute;
  top: 3px;
  right: 3px;
  bottom: 3px;
  width: calc(10.8rem - 3px);
  height: auto;
  transform: none;
  border-left: 2px solid rgba(17, 17, 17, 0.14);
  border-radius: 0;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.55);
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.stack:not([data-card-theme="minimal"]) .card-thumb {
  border-top-left-radius: 14px;
  border-bottom-left-radius: 14px;
  border-top-right-radius: 14px;
  border-bottom-right-radius: 14px;
}

.card-thumb-img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

.card.has-preset-icon .card-thumb {
  top: 50%;
  right: 1rem;
  bottom: auto;
  width: 4.6rem;
  height: 4.6rem;
  transform: translateY(-50%);
  border: 1px solid #ffffff;
  /* Matches the platform icon SVGs' own rx (also 7, on their 64-unit
     viewBox — near enough 1:1 with this tile's rendered px) so the two
     roundings line up instead of showing a mismatched corner. */
  border-radius: 7px;
  /* Solid white, not transparent: the icon SVGs bake in their own rounded
     corners, so a square tile always leaves a sliver where the icon's
     corner falls short of the square. White here matches the border, so
     that sliver reads as part of the border instead of a color gap. */
  background: #ffffff;
}

.card.has-preset-icon .card-thumb-img {
  object-fit: cover;
}

/* ---------- Edit mode (sorting) ---------- */

.card-controls {
  position: absolute;
  top: 50%;
  left: 0.9rem;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
  /* hide: wait for the fade before flipping visibility */
  transition: opacity 0.2s ease, visibility 0s linear 0.2s;
  z-index: 2;
}

.card-move {
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  line-height: 1;
  color: #111;
  background: #fff;
  border: 2px solid #111;
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(17, 17, 17, 0.2);
  transition: transform 0.12s ease, box-shadow 0.12s ease, opacity 0.15s ease;
}

.card-move:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.25);
}

.card-move:active:not(:disabled) {
  transform: translateY(1px);
  box-shadow: 0 1px 0 rgba(17, 17, 17, 0.2);
}

.card-move:disabled {
  opacity: 0.3;
  cursor: default;
}

.stack.editing .card {
  display: block;
  transform: none;
  margin-top: 0.9rem;
  min-height: 11.2rem;
  padding-top: 1rem;
  padding-left: 4.6rem;
  padding-right: 6.2rem;
  padding-bottom: 4.25rem;
  cursor: default;
}

.stack.editing .card .card-thumb {
  top: 1rem;
  right: 1rem;
  bottom: auto;
  width: 4.4rem;
  height: 4.4rem;
  overflow: visible;
  transform: none;
  border: 2px dashed rgba(17, 17, 17, 0.38);
  border-left-width: 2px;
  border-style: dashed;
  border-radius: 14px;
  opacity: 1;
}

.stack.editing .card .card-thumb[hidden] {
  display: block;
}

.stack.editing .card .card-thumb[hidden] .card-thumb-img {
  display: none;
}

.stack.editing .card:first-child {
  margin-top: 0;
}

.stack.editing .card-controls {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  /* show: flip visibility instantly, fade opacity in */
  transition: opacity 0.2s ease, visibility 0s;
}

.stack.editing .card-open {
  display: none;
}

.stack.editing .card-title {
  display: inline-block;
  max-width: 100%;
  padding-right: 0;
  cursor: text;
  outline: none;
  border-bottom: 2px dashed rgba(17, 17, 17, 0.35);
  padding-bottom: 2px;
}

.stack.editing .card-title::after {
  content: " ✎";
  font-size: 0.6em;
  opacity: 0.4;
}

.stack.editing .card-title:focus {
  border-bottom-color: #d97b29;
}

.stack.editing .card-title:focus::after {
  content: "";
}

.stack.editing .card .card-tag {
  display: block;
  width: fit-content;
  max-width: 100%;
  margin-top: 0.3rem;
  cursor: text;
  outline: none;
  caret-color: currentColor;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.stack.editing .card .card-tag:empty {
  display: block;
}

.stack.editing .card .card-tag:focus {
  border-color: #d97b29;
}

.stack.editing .card .card-tag:empty::before {
  content: "add tag";
  opacity: 0.5;
}

/* The card's link — visible + editable only in edit mode */
.card-url {
  display: none;
  font-family: "Poppins", sans-serif;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1.3;
  margin-top: 0.35rem;
  max-width: min(60%, 340px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: 0.7;
}

.stack.editing .card .card-url {
  display: block;
  max-width: 100%;
  font-family: var(--card-font, "Anton"), sans-serif;
  font-size: clamp(0.82rem, 1.7vw, 1rem);
  font-weight: 400;
  letter-spacing: 0.01em;
  line-height: 1.2;
  cursor: text;
  outline: none;
  border-bottom: 1px dashed rgba(17, 17, 17, 0.35);
  min-height: 1.7em;
  padding-bottom: 0.05rem;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

.stack.editing .card .card-url:focus {
  border-bottom-color: #d97b29;
}

.stack.editing .card .card-url:empty::before {
  content: attr(data-placeholder);
  opacity: 0.5;
}

.stack.editing .card .card-description {
  position: static;
  display: block;
  max-width: 100%;
  margin-top: 0.45rem;
  right: auto;
  top: auto;
  opacity: 1;
  transform: none;
  cursor: text;
  outline: none;
  border-bottom: 1px dashed rgba(17, 17, 17, 0.35);
  padding-bottom: 1px;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

.card-edit-actions {
  position: absolute;
  left: 4.6rem;
  right: 1rem;
  bottom: 0.9rem;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.45rem;
  padding-top: 0.65rem;
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
  transition: opacity 0.2s ease, visibility 0s linear 0.2s;
  z-index: 2;
}

.stack.editing .card .card-edit-actions {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transition: opacity 0.2s ease, visibility 0s;
}

.stack.editing .card .card-description:focus {
  border-bottom-color: #d97b29;
}

.stack.editing .card .card-description:empty::before {
  content: "add your description 67 chars max ..";
  opacity: 0.5;
}

.card-url-error {
  color: #d02b2b !important;
  border-bottom-color: #d02b2b !important;
}

/* Delete button in the move-controls column */
.card-delete {
  font-size: 0.75rem;
  color: #c0392b;
}

/* ---------- Card logo images ---------- */

.card-image-btn,
.card-color-btn,
.card-text-color-btn,
.card-font-btn,
.card-border-btn {
  width: 36px;
  height: 36px;
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  color: #111;
  border: 2px solid #111;
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(17, 17, 17, 0.2);
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
  transition: transform 0.12s ease, box-shadow 0.12s ease, opacity 0.2s ease, visibility 0s linear 0.2s;
  z-index: 2;
}

.card-image-btn {
  position: absolute;
  right: -7px;
  bottom: -7px;
  background: #fff;
  z-index: 3;
}

.card-edit-actions .card-color-btn,
.card-edit-actions .card-text-color-btn,
.card-edit-actions .card-font-btn,
.card-edit-actions .card-border-btn {
  position: static;
}

.card-image-btn svg,
.card-color-btn svg,
.card-text-color-btn svg,
.card-font-btn svg,
.card-border-btn svg {
  display: block;
}

.stack.editing .card .card-image-btn,
.stack.editing .card .card-color-btn,
.stack.editing .card .card-text-color-btn,
.stack.editing .card .card-font-btn,
.stack.editing .card .card-border-btn {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transition: transform 0.12s ease, box-shadow 0.12s ease, opacity 0.2s ease, visibility 0s;
}

.card-image-btn:hover,
.card-color-btn:hover,
.card-text-color-btn:hover,
.card-font-btn:hover,
.card-border-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.25);
}

.card-image-btn:active,
.card-color-btn:active,
.card-text-color-btn:active,
.card-font-btn:active,
.card-border-btn:active {
  transform: translateY(1px);
  box-shadow: 0 1px 0 rgba(17, 17, 17, 0.2);
}

.card-thumb-img {
  position: relative;
  z-index: 1;
}

.card.active {
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.08),
    0 16px 28px -8px rgba(0, 0, 0, 0.22);
}

.stack[data-card-theme="minimal"] .card.active {
  transform: scale(1.012);
  box-shadow: none;
  background-image: none;
}

.card.active .card-title {
  opacity: 0;
  transform: translateY(-8px);
}

.card.active .card-tag {
  opacity: 0;
  transform: translateY(-8px);
}

.card.active .card-description {
  opacity: 1;
  transform: translateY(-50%);
}

.card.active .card-open {
  opacity: 1;
  pointer-events: auto;
}

.card.active .card-open:not(:hover):not(:active) {
  transform: translateY(-50%);
}

.card.active .card-thumb {
  opacity: 0;
  transform: translateY(calc(-50% + 8px));
}

/* Hover preview — only on devices that actually support hover (desktop),
   and not while sorting in edit mode */
@media (hover: hover) and (pointer: fine) {
  .stack:not(.editing) .card:hover {
    box-shadow:
      0 2px 4px rgba(0, 0, 0, 0.08),
      0 16px 28px -8px rgba(0, 0, 0, 0.22);
    animation: rock 0.42s ease-in-out 1;
  }

  .stack:not(.editing) .card:hover .card-title {
    opacity: 0;
    transform: translateY(-8px);
  }

  .stack:not(.editing) .card:hover .card-tag {
    opacity: 0;
    transform: translateY(-8px);
  }

  .stack:not(.editing) .card:hover .card-description {
    opacity: 1;
    transform: translateY(-50%);
  }

  .stack:not(.editing) .card:hover .card-open {
    opacity: 1;
    pointer-events: auto;
  }

  .stack:not(.editing) .card:hover .card-open:not(:hover):not(:active) {
    transform: translateY(-50%);
  }

  .stack:not(.editing) .card:hover .card-thumb {
    opacity: 0;
    transform: translateY(calc(-50% + 8px));
  }

  .stack[data-card-theme="minimal"]:not(.editing) .card:hover {
    box-shadow: none;
    transform: scale(1.012);
    animation: none;
    background-image: none;
  }
}

@keyframes rock {
  0%, 100% {
    transform: rotate(var(--tilt)) translateX(var(--nudge));
  }
  25% {
    transform: rotate(calc(var(--tilt) - 1.5deg)) translateX(var(--nudge)) translateY(-2px);
  }
  75% {
    transform: rotate(calc(var(--tilt) + 1.5deg)) translateX(var(--nudge)) translateY(-2px);
  }
}

.image-editor {
  position: fixed;
  inset: 0;
  z-index: 60;
}

.image-editor[hidden] {
  display: none;
}

.image-editor-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(12, 12, 12, 0.55);
  backdrop-filter: blur(4px);
}

.image-editor-modal {
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(92vw, 360px);
  transform: translate(-50%, -50%);
  background: var(--surface);
  color: var(--ink);
  border: 2px solid var(--ink);
  border-radius: 24px;
  padding: 1.1rem;
  box-shadow: 0 22px 60px rgba(0, 0, 0, 0.28);
  outline: none;
}

.image-editor-copy {
  font-family: "Poppins", sans-serif;
  font-size: 0.95rem;
  text-align: center;
  /* Side padding keeps centered text clear of the close button sitting in
     the top-right corner, regardless of exact copy length. */
  padding: 0 2.4rem;
  margin-bottom: 0.8rem;
}

.image-editor-stage {
  display: flex;
  justify-content: center;
}

.image-editor-frame {
  width: 220px;
  height: 220px;
  overflow: hidden;
  position: relative;
  border-radius: 24px;
  background: #e8e8e8;
  border: 2px solid rgba(17, 17, 17, 0.18);
  touch-action: none;
}

/* The profile photo displays circular — crop it inside a round guide too, so
   what's visible while cropping is exactly what survives, corners included. */
.image-editor.profile-crop .image-editor-frame {
  border-radius: 50%;
}

.image-editor-preview {
  position: absolute;
  top: 50%;
  left: 50%;
  transform-origin: center center;
  user-select: none;
  -webkit-user-drag: none;
  will-change: transform;
}

.image-editor-slider-wrap {
  display: grid;
  gap: 0.45rem;
  margin-top: 1rem;
  font-family: "Poppins", sans-serif;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.image-editor-slider {
  width: 100%;
}

.image-editor-actions {
  display: flex;
  gap: 0.55rem;
  justify-content: flex-end;
  margin-top: 1rem;
}

.image-editor-btn {
  border: 2px solid #111;
  border-radius: 999px;
  background: #fff;
  color: #111;
  font-family: "Archivo Black", sans-serif;
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  padding: 0.7rem 0.95rem;
  cursor: pointer;
}

.logo-chooser-modal,
.icon-chooser-modal {
  width: min(92vw, 420px);
}

.logo-chooser-close {
  position: absolute;
  top: 0.8rem;
  right: 0.8rem;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid #111;
  border-radius: 999px;
  background: #fff;
  color: #111;
  font-family: "Archivo Black", sans-serif;
  font-size: 0.85rem;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(17, 17, 17, 0.2);
}

.logo-chooser-actions {
  display: grid;
  gap: 0.65rem;
}

.logo-chooser-actions .image-editor-btn {
  width: 100%;
  justify-content: center;
}

.logo-chooser-remove {
  color: #b42318;
}

.icon-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.75rem;
}

.icon-choice {
  display: grid;
  gap: 0.45rem;
  justify-items: center;
  align-content: start;
  border: 2px solid rgba(17, 17, 17, 0.14);
  border-radius: 18px;
  background: rgba(255, 255, 255, 0.72);
  padding: 0.75rem 0.5rem 0.65rem;
  cursor: pointer;
}

.icon-choice.selected {
  border-color: #d97b29;
  box-shadow: 0 0 0 2px rgba(217, 123, 41, 0.14);
}

.icon-choice-img {
  width: 52px;
  height: 52px;
  display: block;
}

.icon-choice-label {
  font-family: "Poppins", sans-serif;
  font-size: 0.74rem;
  font-weight: 700;
  line-height: 1.15;
  text-align: center;
}

.image-editor-remove {
  margin-right: auto;
  color: #b42318;
}

/* ---------- Bio ---------- */
/* Linktree-style: plain centered text under the name, always visible, no
   heading and no bordered "panel" chrome (that made sense when this was a
   click-to-expand accordion; it's static content now). */

.about-accordion {
  max-width: 460px;
  width: 100%;
  margin: 0.1rem auto 0.5rem;
  padding: 0 1.5rem;
  box-sizing: border-box;
}

.bio-text {
  margin: 0;
  font-family: var(--title-font, "Poppins"), sans-serif;
  font-size: 0.92rem;
  line-height: 1.4;
  text-align: center;
  color: var(--ink);
  opacity: 0.72;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: break-word;
  outline: none;
}

.bio-text.title-caps {
  text-transform: uppercase;
}

body.editing .bio-text {
  opacity: 1;
  cursor: text;
  border-bottom: 2px dashed rgba(17, 17, 17, 0.3);
  padding-bottom: 3px;
}

:root.dark body.editing .bio-text {
  border-bottom-color: rgba(255, 255, 255, 0.3);
}

body.editing .bio-text:focus {
  border-bottom-color: #d97b29;
}

/* No separate footer section anymore — "Forgot your page link?" lives in
   the top-right menu dropdown instead (see .site-menu). Owner-mode boards
   already have working access to their own link — nothing to recover, so
   it stays hidden there. Shared-view visitors (someone else's board) DO
   still get it: the recovery flow is a plain email lookup, independent of
   whichever board they're currently looking at — same reasoning as
   offering "Create your own" there too. */
body.owner-mode #forgotLinkBtn {
  display: none;
}

@media (max-width: 640px) {
  .card {
    min-height: 6.4rem;
    padding: 1.15rem 1.4rem;
    margin-top: -0.7rem;
  }

  .card:first-child {
    margin-top: 0;
  }

  .card-description {
    left: 1.4rem;
    right: 8.4rem;
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }

  .card-open {
    right: 0.9rem;
    font-size: 0.75rem;
    padding: 0.6rem 0.95rem;
  }

  .card-thumb {
    top: 3px;
    right: 3px;
    bottom: 3px;
    width: calc(7.2rem - 3px);
  }

  .card.has-preset-icon .card-thumb {
    top: 50%;
    right: 0.75rem;
    bottom: auto;
    width: 3.9rem;
    height: 3.9rem;
    transform: translateY(-50%);
  }

  .card-controls {
    left: 0.7rem;
    gap: 0.3rem;
  }

  .card-move {
    width: 32px;
    height: 32px;
    font-size: 0.7rem;
  }

  .stack.editing .card {
    min-height: 12.1rem;
    padding-top: 0.9rem;
    padding-left: 3.6rem;
    padding-right: 5rem;
    padding-bottom: 4.55rem;
  }

  .stack.editing .card .card-thumb {
    width: 3.7rem;
    height: 3.7rem;
    top: 0.8rem;
    right: 0.8rem;
  }

  .card-image-btn,
  .card-color-btn,
  .card-text-color-btn,
  .card-font-btn,
  .card-border-btn {
    width: 32px;
    height: 32px;
  }

  .card-edit-actions {
    left: 3.6rem;
    right: 0.8rem;
    bottom: 0.8rem;
    gap: 0.35rem;
    padding-top: 0.55rem;
  }

  .card-title {
    padding-right: 5.4rem;
  }

  .card-tag {
    max-width: calc(100% - 5.4rem);
  }

  .stack.editing .card-title,
  .stack.editing .card .card-tag,
  .stack.editing .card .card-url,
  .stack.editing .card .card-description {
    max-width: 100%;
  }

  /* Mobile browsers (iOS Safari and Chrome alike) zoom the viewport in
     whenever a focused field's font-size is under 16px, then don't reliably
     zoom back out on blur — bumping these editable fields to 16px while
     editing avoids the zoom happening at all, instead of trying to undo it
     after the fact. .card-title/.board-title are already well above 16px
     and don't need this. */
  .stack.editing .card .card-tag,
  .stack.editing .card .card-url,
  .stack.editing .card .card-description,
  body.editing .bio-text,
  #slugInput {
    font-size: 16px;
  }

  .image-editor-frame {
    width: 200px;
    height: 200px;
  }

  .speech-bubble.color-bubble {
    width: min(260px, calc(100vw - 16px));
  }

  .stack-toolbar {
    flex-wrap: wrap;
  }

  .theme-select-btn {
    margin-left: 0 !important;
  }

  /* Link/copy rows (save modal + share modal): side-by-side leaves the
     input too narrow to show more than a fragment of the URL. Stacking the
     COPY button underneath instead gives the input the full row width. */
  .save-link-line {
    flex-direction: column;
  }
}

/* ---------- Owned boards: loading + save modal ---------- */

/* /b/<id> pages fetch the board before first meaningful paint — hide the
   placeholder defaults so they never flash. */
body.board-loading .board-title-wrap,
body.board-loading .profile-image,
body.board-loading .about-accordion,
body.board-loading .stack-toolbar,
body.board-loading .stack,
body.board-loading .stack-actions {
  visibility: hidden;
}

.save-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(17, 17, 17, 0.55);
}

.save-modal {
  position: relative;
  background: var(--surface);
  color: var(--ink);
  border: 2px solid var(--ink);
  border-radius: 20px;
  box-shadow: 0 8px 0 rgba(17, 17, 17, 0.25);
  max-width: 560px;
  width: 100%;
  padding: 1.4rem 1.4rem 1.15rem;
}

.save-modal-close {
  position: absolute;
  top: 0.8rem;
  right: 0.8rem;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "Archivo Black", sans-serif;
  font-size: 0.85rem;
  color: var(--ink);
  background: #fff;
  border: 2px solid var(--ink);
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(17, 17, 17, 0.2);
}

.save-modal-close:hover {
  transform: translateY(-1px);
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.25);
}

.save-modal-close:active {
  transform: translateY(1px);
  box-shadow: 0 1px 0 rgba(17, 17, 17, 0.2);
}

.save-modal h2 {
  font-family: "Archivo Black", sans-serif;
  font-size: 1.35rem;
  text-transform: uppercase;
  margin: 0 0 0.75rem;
}

.save-modal-intro {
  font-size: 0.9rem;
  margin: 0 0 1rem;
}

.save-modal-warning {
  font-weight: 700;
  font-size: 0.88rem;
  line-height: 1.45;
  background: #eef25a;
  color: #111;
  border: 2px solid #111;
  border-radius: 12px;
  padding: 0.65rem 0.85rem;
  margin: 0 0 1rem;
}

.save-link-row {
  margin-bottom: 0.9rem;
}

.save-link-label {
  display: block;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  opacity: 0.7;
  margin-bottom: 0.3rem;
}

.save-link-line {
  display: flex;
  gap: 0.5rem;
}

.save-link-line input {
  flex: 1;
  min-width: 0;
  font-family: "Space Mono", monospace;
  /* Same iOS zoom-on-focus threshold as .owner-email-input above — this
     field gets focus()'d both on tap-to-select and on clipboard-blocked
     copy fallback. */
  font-size: 16px;
  padding: 0.5rem 0.6rem;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--surface);
  color: var(--ink);
}

.owner-email-row {
  margin: 0 0 1rem;
}

.owner-email-label {
  font-size: 0.8rem;
  font-weight: 600;
  margin: 0 0 0.4rem;
}

.owner-email-line {
  display: flex;
  gap: 0.5rem;
}

.owner-email-input {
  flex: 1;
  min-width: 0;
  font-family: inherit;
  /* iOS Safari/Chrome force-zoom the viewport on focus for any input under
     16px font-size — this gets auto-focused the instant the modal opens
     (see emailInput.focus() in showRecoverModal), so anything smaller here
     zoomed the page in immediately, before the user tapped anything. */
  font-size: 16px;
  padding: 0.5rem 0.6rem;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--surface);
  color: var(--ink);
}

.owner-email-input:focus {
  outline: none;
  border-color: #d97b29;
}

.owner-email-status {
  margin: 0.4rem 0 0;
  font-size: 0.78rem;
  min-height: 1em;
}

.owner-email-status.is-error {
  color: #d02b2b;
}

.save-modal-btn {
  font-family: "Archivo Black", sans-serif;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: #111;
  background: #fff;
  border: 2px solid #111;
  border-radius: 999px;
  padding: 0.45rem 0.9rem;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(17, 17, 17, 0.2);
  white-space: nowrap;
}

.save-modal-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 3px 0 rgba(17, 17, 17, 0.25);
}

.save-modal-btn:active {
  transform: translateY(1px);
  box-shadow: 0 1px 0 rgba(17, 17, 17, 0.2);
}

.save-modal-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.4rem;
}

.save-modal-open {
  background: #eef25a;
}

/* Share modal: copy-link is the main event (styled via .save-link-row
   above) — this icon row is a secondary, deliberately smaller convenience
   underneath it, not a second focal point competing with the link itself. */
.share-icon-row {
  display: flex;
  justify-content: center;
  flex-wrap: nowrap;
  gap: 0.35rem;
  margin-top: 1rem;
  padding-top: 0.85rem;
  border-top: 2px solid rgba(17, 17, 17, 0.1);
}

.share-icon-btn {
  display: block;
  background: none;
  border: none;
  padding: 0.1rem;
  cursor: pointer;
}

.share-icon-img {
  width: 30px;
  height: 30px;
  display: block;
  border-radius: 8px;
}
