/* ══════════════════════════════════════════════════════════════
   Meetback — public card (recipient view at /c/{slug})

   Lifted from the pinned reference
   design-system/products/meetback/assets/public-card.html @ 06f73e97.

   Scoped under `.public-card` so its own palette cannot leak — this screen
   redefines --surface/--border/--text/--muted, which the app screens also use.
   --profile, --profile-lt and --profile-dk are set inline by the module from
   card.accent; they drive the whole hero and the Save Contact pill.

   Uses Fraunces for the name (the Meetback identity mark) and Inter for
   everything else, both already loaded by the shell.

   ── Q24: THE ACCENT IS A SURFACE HERE, NEVER TEXT ──────────────
   Owner, 2026-08-06: "keep black font color for the preview/sharing page."

   --profile is whatever colour the owner picked in the editor, and NOTHING
   constrains it. As a background that is exactly right — it is where the
   card's identity is supposed to live, and white sits on it under a text
   shadow. As TEXT it was a coin toss, and the recipient — the one person who
   cannot change it — got whichever the owner happened to like.

   MEASURED, and the first number is the one worth reading twice: on the
   initials' near-white gradient the DEFAULT indigo already sat at 3.65:1,
   below AA, before anybody picked anything unusual. A pale yellow was 1.16:1.
   On the white sheet the same indigo is 4.50:1 — AA to two decimal places —
   and the yellow 1.43:1. This was never only about bright colours; the shipped
   default was already failing.

   Four sites carried it and all four now take the sheet's own ink
   (--pc-text): the initials (the largest text on the page), the Save Contact
   pill, the Read more link and the lead-capture button. The hero, the tint,
   the borders, the color-mix washes and the retry button's BACKGROUND are
   untouched — none of them is text on white.

   tests/gates/legible_accent_text.mjs is what keeps this true. It computes the
   real WCAG ratio for every one of these sites across a spread of accents, and
   it refuses any NEW `color: var(--profile)` on this file that is not
   registered with the surface behind it and a reason.
   ══════════════════════════════════════════════════════════════ */

.public-card {
  --pc-surface: #fff;
  --pc-border: var(--pc-line);
  --pc-text: #0f1220;
  --pc-muted: var(--ch-muted);
  --profile: var(--profile-fallback);
  --profile-dk: var(--profile-fallback-dk);
  --profile-lt: var(--profile-fallback-lt);
  /* Q41-A — ONE SOURCE for the portrait's size, because two things now depend on
     it: its own width, and how far it is pulled up into the curve. Two copies of
     this clamp would let the seat drift off the curve at one screen width only,
     which is the class of bug that only ever shows up on somebody's phone. */
  --pc-face: clamp(120px, 34vw, 152px);

  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  max-width: 460px;
  margin: 0 auto;
  background: var(--pc-surface);
  color: var(--pc-text);
  font-family: var(--font-body);
  display: flex;
  flex-direction: column;
  overflow-y: auto;              /* hero + content scroll as one, per the spec */
  -webkit-overflow-scrolling: touch;
}

/* ── hero ── */
/* ── Q41, DIRECTION A — THE CURVE CRADLES THE FACE ───────────────────────
   Owner, 2026-08-08, said it twice in one message. The swept edge becomes a
   SEAT: the portrait sits at its lowest point, half on colour and half on
   white, and every word drops below it onto white.

   ⚠ THE CURVE ITSELF IS FIXED AND NOT RE-OPENABLE. Same path production has
   always drawn — M0,0 Q200,60 400,0 L400,52 L0,52 Z — read out of the code
   rather than redrawn by eye. Owner, twice: "I already mentioned that I like
   curved background it has now." A direction that replaces it with a straight
   edge, a rectangle or a tear line is not a direction.

   ⚠ THE MEASURED CHANGE IS THE SUBSTANCE, not the look: the coloured field goes
   from clamp(340px, 49dvh, 520px) to 250px. Before this the field carried the
   portrait, the name, the role, the location AND the button before the curve
   arrived — so on a 667pt screen the first real fact was already below the fold,
   and every one of those words needed a text-shadow to survive a pale accent.
   Now the field carries the mark and nothing else. */
.public-card .hero {
  position: relative; overflow: hidden; background: var(--profile); text-align: center;
  padding: calc(16px + var(--sat)) clamp(26px, 7vw, 36px) 0;
  color: var(--pc-surface); display: flex; flex-direction: column;
  min-height: 250px; flex: 0 0 auto;
}
.public-card .hero-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.public-card .hero-tint {
  position: absolute; inset: 0; z-index: 1; transition: opacity .2s;
  background: linear-gradient(165deg, var(--profile-lt) 0%, var(--profile) 52%, var(--profile-dk) 100%);
}
.public-card .hero.has-cover .hero-tint { opacity: .58; }
.public-card .hero::before {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background: radial-gradient(120% 70% at 80% 0%, rgba(255, 255, 255, .22), transparent 55%);
}
/* Legibility safety net — independent of the tint, so white text never depends
   on a photo failing to load or on a very light profile colour.
   ⚠ ONLY `.top` IS LEFT ON THE COLOUR (Q41-A). The name, the location and the
   role are on white now and take the surface's ink, which is Q24's rule rather
   than a new one — and a shadow under black text on white is not a safety net,
   it is a smudge. Removing it here is the point of moving them, not a detail
   that came along with it. */
.public-card .top {
  display: flex; align-items: center; justify-content: space-between;
  position: relative; z-index: 2; min-height: 36px;
  text-shadow: 0 1px 6px rgba(10, 14, 40, .25);
}

/* ── the seat ──
   `.id` is now a sibling of the hero, on white, and the avatar is pulled UP into
   the curve. It could not stay inside the hero: `.hero` has `overflow: hidden`,
   so a portrait sticking out of its bottom edge would be clipped in half rather
   than straddling anything.

   THE OFFSET IS DERIVED FROM THE PATH, NOT EYEBALLED. The curve element is 52px
   tall and sits at the hero's bottom edge; its quadratic runs (0,0)→(400,0) with
   control (200,60), so at the centre it reaches y = 0.25·0 + 0.5·60 + 0.25·0 =
   30 of 52. The colour therefore ends 22px above the hero's bottom edge at the
   centre — which is exactly where a seated face's centre belongs. Half above,
   half below, from the geometry rather than from a number that looked right. */
.public-card .id {
  position: relative; z-index: 3; width: 100%;
  background: var(--pc-surface); text-align: center;
  padding: 0 clamp(26px, 7vw, 36px) 4px;
}
.public-card .id .avatar { margin-top: calc(-22px - var(--pc-face) / 2); }
.public-card .pro {
  border: 1.5px solid rgba(255, 255, 255, .8); border-radius: 100px; padding: 4px 12px;
  font-size: 12px; font-weight: 800; letter-spacing: .04em;
}
.public-card .share {
  width: 36px; height: 36px; border-radius: 50%; background: rgba(255, 255, 255, .18);
  display: grid; place-items: center; cursor: pointer; margin-left: auto; transition: .15s;
}
.public-card .share svg { width: 19px; height: 19px; }
.public-card .share.copied { background: rgba(255, 255, 255, .45); }
.public-card .share:focus-visible { outline: 2px solid var(--pc-surface); outline-offset: 2px; }

.public-card .avatar {
  width: var(--pc-face); aspect-ratio: 1; border-radius: 50%; overflow: hidden;
  background: var(--pc-surface); margin: 0 auto; position: relative; z-index: 2;
  box-shadow: 0 0 0 4px #fff, 0 10px 28px rgba(10, 20, 60, .42);
}
.public-card .avatar img { width: 100%; height: 100%; object-fit: cover; }
.public-card .avatar .mono {
  width: 100%; height: 100%; display: grid; place-items: center;
  background: linear-gradient(160deg, var(--mono-1), var(--mono-2));
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(38px, 11vw, 48px); color: var(--pc-text); text-shadow: none;
}
.public-card .name {
  font-family: var(--font-display); font-optical-sizing: auto; font-weight: 700;
  color: var(--pc-text);
  font-size: clamp(26px, 7.6vw, 33px); letter-spacing: -.01em; margin-top: 16px;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  position: relative; z-index: 2;
}
.public-card .name .vf { width: clamp(18px, 5vw, 22px); height: clamp(18px, 5vw, 22px); flex: 0 0 auto; }
/* Ink from the surface, and a muted token rather than `opacity` — an opacity on
   white ink is a grey nobody chose and one the contrast gate cannot reason about. */
.public-card .loc { font-size: clamp(13px, 3.6vw, 14px); color: var(--slate-700); margin-top: 4px; position: relative; z-index: 2; }
.public-card .role { font-size: clamp(15px, 4.2vw, 17px); font-weight: 700; color: var(--pc-text); margin-top: 14px; position: relative; z-index: 2; }
/* ⚠ THE BUTTON INVERTS, AND IT HAS TO. It was a white pill on the accent; on
   white it would be white on white — the one change in direction A that is
   forced rather than chosen.
   IT DOES NOT BECOME AN ACCENT PILL, and that is deliberate. An accent
   background needs ink chosen per accent, and this project has already measured
   what happens when that is assumed: the owner's own accent put text at 1.16:1
   and the DEFAULT accent failed AA at 3.65:1. There is no token that answers
   "what is legible on an arbitrary accent", so inventing one here would be a
   contrast decision smuggled in as a button colour.
   Ink on white is unambiguous at every accent, needs nothing new, and is
   consistent with A's whole premise: the accent is the FIELD, and everything
   that has to be read sits on white. */
.public-card .cta {
  display: inline-block; margin: 18px auto 0; background: var(--pc-text); color: var(--pc-surface);
  font-family: var(--font-body); font-weight: 700; font-size: clamp(15px, 4vw, 16px);
  padding: 13px 44px; border-radius: 100px; border: none; cursor: pointer;
  box-shadow: 0 8px 20px rgba(10, 20, 60, .25); position: relative; z-index: 2;
}
/* The ring was white, because the button sat on the accent. On white it has to
   be ink, or the focus ring is invisible on the surface it is drawn against —
   the same inversion as the button itself. */
.public-card .cta:focus-visible { outline: 2px solid var(--pc-text); outline-offset: 3px; }
.public-card .hero-pad { height: 44px; }
.public-card .curve { position: absolute; left: 0; right: 0; bottom: -1px; width: 100%; height: 52px; display: block; z-index: 2; }

/* ── white content ── */
.public-card .body { flex: 1 0 auto; display: flex; flex-direction: column; justify-content: center; padding: 6px 0; }
.public-card .sec { padding: 20px clamp(26px, 7vw, 36px) 0; }
.public-card .sec-h { text-align: center; font-weight: 800; font-size: clamp(17px, 4.6vw, 19px); margin-bottom: 12px; }
.public-card .summary {
  font-size: 14px; line-height: 1.55; color: var(--slate-700); text-align: center;
  max-width: 36ch; margin: 0 auto;
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
.public-card .summary.expanded { -webkit-line-clamp: unset; display: block; }
/* Q24 — ink, not the accent, and the UNDERLINE is what pays for it. This is
   the one site here whose accent was doing a second job: it said "tappable".
   Taking the colour away without replacing that signal would obey the owner's
   instruction and leave a control nobody can see is one. */
.public-card .readmore {
  display: block; text-align: center; color: var(--pc-text); font-weight: 700;
  text-decoration: underline; text-underline-offset: 3px;
  font-size: 13.5px; margin-top: 12px; cursor: pointer;
}
.public-card .readmore:focus-visible { outline: 2px solid var(--profile); outline-offset: 2px; border-radius: 6px; }
.public-card .rule { height: 1px; background: var(--pc-border); margin: 24px clamp(26px, 7vw, 36px); }

.public-card .connect { padding: 0 clamp(26px, 7vw, 36px) 8px; }
.public-card .conn-row { display: flex; justify-content: center; flex-wrap: wrap; gap: 26px; margin-top: 6px; }
/* The reference draws these as <span>. Live they are real controls — an <a> for
   an item with a destination, a <button> for one whose value is copied — so the
   element resets are here rather than the appearance changing. */
.public-card .conn {
  width: 46px; height: 46px; display: grid; place-items: center;
  color: var(--pc-text); cursor: pointer;
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; text-decoration: none; -webkit-tap-highlight-color: transparent;
  border-radius: 12px; transition: transform .12s, background .15s;
}
.public-card .conn svg { width: 32px; height: 32px; }
.public-card .conn .let { font-weight: 800; font-size: 24px; }
.public-card .conn:focus-visible { outline: 2px solid var(--profile); outline-offset: 2px; }
.public-card .conn:active { transform: scale(.94); }
/* Copied — the same acknowledgement the share control uses, for the same reason:
   a tap that hands something over has to look like it did something. */
.public-card .conn.copied { background: color-mix(in srgb, var(--profile) 14%, var(--pc-surface)); }

/* ── the status line ───────────────────────────────────────────
   Sticky rather than in flow: this page is one long scroller, and a
   confirmation written into the column under the Connect row is off-screen for
   anyone who has scrolled past it — which is the same defect that put a failed
   delete 1534px below the fold on Contacts. Collapses to nothing when empty.

   NEVER display-toggled, and never inserted at the moment its text changes: a
   live region that appears with its content is not reliably announced. It stays
   in the DOM and in the layout, and collapses to nothing because .pc-msg:empty
   is `display:none` — same construction as contacts.js, for the same reason. */
.public-card .pc-status {
  position: sticky; bottom: 0; z-index: 4;
  padding: 0 clamp(26px, 7vw, 36px);
  pointer-events: none;
}
.public-card .pc-status.on { padding-bottom: calc(8px + var(--sab)); }
.public-card .pc-msg {
  margin: 8px auto 0; max-width: 34ch; text-align: center;
  background: rgba(15, 18, 32, .92); color: var(--pc-surface); border-radius: 12px;
  padding: 9px 14px; font-size: 12.5px; line-height: 1.35;
  box-shadow: 0 8px 22px rgba(10, 20, 60, .28); overflow-wrap: anywhere;
}
.public-card .pc-msg:empty { display: none; }

/* Answered from this device's cache — shown, but not presented as current. */
.public-card .pc-stale {
  margin: 14px clamp(26px, 7vw, 36px) 0; padding: 9px 12px;
  border: 1px solid var(--pc-border); border-radius: 12px;
  background: var(--surface-1); color: var(--pc-muted);
  font-size: 12px; line-height: 1.4; text-align: center;
}

/* ── lead capture (entry card only — the form is a separate deliverable) ── */
.public-card .lead { padding: 0 clamp(26px, 7vw, 36px); margin-top: 22px; display: none; }
.public-card .lead.on { display: block; }
.public-card .lead-card {
  background: color-mix(in srgb, var(--profile) 6%, var(--pc-surface));
  border: 1px solid color-mix(in srgb, var(--profile) 20%, var(--pc-surface));
  border-radius: 16px; padding: 16px 18px; text-align: center;
}
.public-card .lead-card .t { font-size: 14px; font-weight: 700; color: var(--pc-text); }
.public-card .lead-card .d { font-size: 12.5px; color: var(--pc-muted); margin: 4px 0 12px; line-height: 1.4; }
.public-card .lead-btn {
  width: 100%; padding: 12px; border-radius: 12px; border: 1.5px solid var(--profile);
  background: transparent; color: var(--pc-text); font-family: var(--font-body);
  font-weight: 700; font-size: 14px; cursor: pointer;
}
/* Kept for the states that still disable it — the send button while a write is
   in flight inherits nothing from here, but a disabled entry control should
   never look identical to a live one. */
.public-card .lead-btn[disabled] {
  cursor: default; opacity: .55;
  border-color: color-mix(in srgb, var(--profile) 40%, var(--pc-surface));
}
.public-card .lead-note {
  margin: 8px 0 0; font-size: 11.5px; line-height: 1.4; color: var(--pc-muted);
}

/* ── the form itself (Q42 reopen · D19 ruled the field set) ──────────────
   ⚠ NO `color: var(--profile)` ANYWHERE BELOW, and that is Q24 rather than
   taste: legible_accent_text.mjs registers every accent-as-text site in this
   file, and the accent here is a colour the READER cannot change. The accent
   is a border and a wash; the ink is --pc-text and --pc-muted. */
.public-card .lead-form { margin-top: 12px; text-align: left; }
.public-card .lead-form .lf {
  display: block; margin-bottom: 10px;
  font-size: 11.5px; font-weight: 700; color: var(--pc-muted);
  letter-spacing: .01em;
}
.public-card .lead-form .lf .opt { font-weight: 500; opacity: .8; }
.public-card .lead-form input,
.public-card .lead-form textarea {
  display: block; width: 100%; margin-top: 4px; padding: 10px 12px;
  border: 1px solid var(--pc-border); border-radius: 12px;
  background: var(--pc-surface); color: var(--pc-text);
  font-family: var(--font-body); font-weight: 500;
  /* 16px is not a size choice — anything under it makes iOS Safari ZOOM the
     page on focus, and this form sits inside a hero the zoom then crops. */
  font-size: 16px; line-height: 1.35;
}
.public-card .lead-form textarea { resize: vertical; min-height: 44px; }
.public-card .lead-form input:focus-visible,
.public-card .lead-form textarea:focus-visible {
  outline: 2px solid var(--profile); outline-offset: 1px; border-color: transparent;
}
.public-card .lead-err {
  margin: 0 0 10px; font-size: 12px; line-height: 1.4;
  /* --del is the app's ONE red (Q30, tokens.css). A second red invented here
     for "you left the name blank" would be a second destructive palette, which
     is precisely what that token exists to prevent — and one_palette refuses a
     literal anyway. Q24 still binds: the sentence carries the meaning. */
  color: var(--del); font-weight: 600;
}
.public-card .lead-acts { display: flex; gap: 8px; }
.public-card .lead-cancel, .public-card .lead-go {
  flex: 1 1 0; padding: 12px; border-radius: 12px;
  font-family: var(--font-body); font-weight: 700; font-size: 14px; cursor: pointer;
}
.public-card .lead-cancel {
  border: 1px solid var(--pc-border); background: transparent; color: var(--pc-muted);
}
.public-card .lead-go {
  border: 1.5px solid var(--profile); color: var(--pc-text);
  background: color-mix(in srgb, var(--profile) 14%, var(--pc-surface));
}
.public-card .lead-go[disabled] { cursor: default; opacity: .6; }
.public-card .lead-done {
  margin: 10px 0 0; font-size: 13px; font-weight: 700; color: var(--pc-text);
}

.public-card .brand {
  text-align: center; padding: 22px 0 calc(20px + var(--sab));
  font-size: 11px; font-weight: 800; letter-spacing: .12em; color: var(--slate-300); flex: 0 0 auto;
}

/* ── unknown slug ──────────────────────────────────────────────
   Not in the reference, which draws a found card only. A stranger following a
   dead link is a real state and cannot be left blank; built from the same
   parts, no new visual language. The designer has not ruled on it — see
   STATUS.md, alongside the same question for /t/{id}. */
.public-card.pc-empty { justify-content: center; text-align: center; }
.public-card .pc-empty-inner { flex: 1 1 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 32px; gap: 12px; }
.public-card .pc-empty-mark {
  font-family: var(--font-display); font-weight: 600; font-size: clamp(30px, 8vw, 38px);
  letter-spacing: -.02em; color: var(--pc-text);
}
.public-card .pc-empty-note { font-size: var(--t-sm); line-height: 1.5; color: var(--pc-muted); max-width: 30ch; }

/* ── could-not-look ────────────────────────────────────────────
   A DIFFERENT STATE FROM "no such card", and it has to look different or the
   distinction lives only in the source. Same parts, one retry. */
.public-card .pc-empty-sub { font-size: 12px; color: var(--pc-muted); }
.public-card .pc-slug { display: inline-block; font-weight: 700; color: var(--pc-text); }
.public-card .pc-retry {
  margin-top: 4px; padding: 12px 30px; border-radius: 100px; border: 0;
  background: var(--profile); color: var(--pc-surface); font-family: var(--font-body);
  font-weight: 700; font-size: 15px; cursor: pointer;
}
.public-card .pc-retry:focus-visible { outline: 2px solid var(--profile); outline-offset: 3px; }

/* ── loading ───────────────────────────────────────────────────
   Painted before the query is issued. Built from the hero's own parts so the
   card does not jump into a different layout when it lands; a blank #app was
   indistinguishable from a dead link for the whole of a slow cold load. */
.public-card.pc-loading .hero-tint { opacity: 1; }
.public-card .pc-skel {
  display: block; border-radius: 100px;
  background: rgba(255, 255, 255, .28);
  animation: pc-pulse 1.4s ease-in-out infinite;
}
.public-card .pc-skel-av { width: 100%; height: 100%; border-radius: 50%; }
.public-card .pc-skel-name { width: min(62%, 220px); height: clamp(26px, 7.6vw, 33px); margin: 16px auto 0; }
.public-card .pc-skel-role { width: min(42%, 150px); height: clamp(15px, 4.2vw, 17px); margin: 14px auto 0; }
.public-card .pc-loading-note {
  text-align: center; padding: 24px clamp(26px, 7vw, 36px);
  font-size: var(--t-sm); color: var(--pc-muted);
}
@keyframes pc-pulse { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .public-card * { transition: none !important; }
  .public-card .pc-skel { animation: none; }
}

/* Q7 — the recipient card scrolls: the hero (the card's OWN accent) is at the
   top, the white action area at the bottom. --profile resolves here because
   public-card.js sets it inline on this very root, so the top band follows the
   card's colour, per card. The canvas stays the page surface for the bottom. */
body:has([data-screen="public-card"]) { background: var(--surface); }
[data-screen="public-card"] { --edge-top: var(--profile, var(--surface)); }

/* ── Q63: autofill takes this surface's own colours. The reasoning and the
   box-shadow trap are written out once, in editor.css. ── */

.public-card .lead-form input:-webkit-autofill,
.public-card .lead-form textarea:-webkit-autofill,
.public-card .lead-form input:-webkit-autofill:hover,
.public-card .lead-form input:-webkit-autofill:focus,
.public-card .lead-form input:-webkit-autofill:active {
  box-shadow: 0 0 0 1000px var(--pc-surface) inset;
  -webkit-text-fill-color: var(--pc-text);
  caret-color: var(--pc-text);
}

