:root {
  color-scheme: light dark;
    --fg: darkgoldenrod;
    --bg: #103050;
    --panel-bg: #204060;
    --button-bg: #406080;
    --border: #3a3a40;
    --shadow: rgb(0 0 0 / 45%);
    --muted-fg: tan;
    --editor-fg: #E2BC83;
}

@media (prefers-color-scheme: dark) {
  :root {
    --fg: darkgoldenrod;
    --bg: #103050;
    --panel-bg: #204060;
    --button-bg: #406080;
    --border: #3a3a40;
    --shadow: rgb(0 0 0 / 45%);
    --muted-fg: #9e9280;
    --editor-fg: #E2BC83;
  }
}

/* Below the device cap, .viewport-frame shrinks with the real viewport (min(100vw, 480px)), so fixed-px sizing
   inside it stops scaling and can overflow or look disproportionate on narrower screens. Above the cap the
   frame is pinned at exactly 480px regardless of how much wider the real viewport is, so fixed sizes are both
   safe and preferable there (vw-relative sizing would otherwise keep growing past the cap forever). These two
   blocks carry the same design at two different units for exactly that reason: everything under .card-message-*
   reads one or the other depending on which regime is currently active, so there's a single place to retune
   either one. The vw values are chosen to roughly match their fixed counterparts at the 480px boundary itself.
*/
:root {
  --message-font-size: 5vw;
  --message-panel-padding: 3.3vw;
  --message-panel-radius: 2.5vw;
  --message-gap: 2vw;
  --message-editor-padding: 1.7vw;
  --message-editor-radius: 1.7vw;
  --message-button-width: 23vw;
  --message-button-padding-block: 1.7vw;
}

@media (min-width: 481px) {
  :root {
    --message-font-size: 18pt;
    --message-panel-padding: 1rem;
    --message-panel-radius: 12px;
    --message-gap: 0.6rem;
    --message-editor-padding: 0.5rem;
    --message-editor-radius: 8px;
    --message-button-width: 7rem;
    --message-button-padding-block: 0.5rem;
  }
}

html,
body {
  /* `dvh` tracks the *currently visible* viewport (falls back to `vh` on browsers that don't support it, since
     an unsupported value in a declaration is ignored, leaving the first one in effect). Plain `vh` is defined as
     the *largest* possible viewport on mobile Safari/Chrome-on-iOS — it doesn't shrink when the address bar or
     bottom toolbar are showing, so content sized with it ends up partly hidden behind them instead of resizing. */
  height: 100vh;
  height: 100dvh;
  margin: 0;
}

body {
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--bg);
  color: var(--fg);
  font-family: "Nunito", system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* Always-present simulated mobile viewport, capped at the assumed device's maximum resolution. It fills the
   real viewport edge-to-edge when that viewport is within the cap in both dimensions, and otherwise sits
   centered with a visible boundary so it reads as a simulated phone rather than a broken layout. */
.viewport-frame {
  box-sizing: border-box;
  width: min(100vw, 480px);
  height: min(100vh, 960px);
  height: min(100dvh, 960px);
  overflow: hidden;
  background: var(--panel-bg);
}

@media (min-width: 481px), (min-height: 961px) {
  .viewport-frame {
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 1rem 3rem var(--shadow);
  }
}

.card-message {
  display: flex;
  height: 100%;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  text-align: center;
  color: var(--muted-fg);
}

.card-grid {
  box-sizing: border-box;
  display: grid;
  width: 100%;
  height: 100%;
}

.card-photo {
  display: block;
  grid-column: 3 / 6;
  grid-row: 3;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}

.card-name,
.card-designation,
.card-tagline {
  display: flex;
  align-items: center;
  justify-content: center;
  grid-column: 2 / 7;
  overflow: hidden;
  white-space: nowrap;
  text-align: center;
  text-overflow: ellipsis;
}

.card-name {
  grid-row: 5;
  font-weight: 700;
  margin-bottom: -2vh;
}

.card-designation {
  grid-row: 7;
  font-weight: 500;
  color: var(--muted-fg);
}

.card-tagline {
  grid-row: 9;
  color: var(--muted-fg);
  font-style: italic;
}

.card-link {
  display: flex;
  align-items: center;
  overflow: hidden;
  color: var(--fg);
  font-weight: 600;
  text-decoration: underline;
  text-overflow: ellipsis;
  text-underline-offset: 0.15em;
  white-space: nowrap;
}

.card-link-resume {
  grid-column: 3;
  grid-row: 11;
  text-align: right;
  justify-content: right;
}

.card-link-linkedin {
  grid-column: 5;
  grid-row: 11;
  text-align: left;
  justify-content: left;
}

.card-link-13-left {
  grid-column: 3;
  grid-row: 13;
  text-align: right;
  justify-content: right;
}

.card-link-13-right {
  grid-column: 5;
  grid-row: 13;
  text-align: left;
  justify-content: left;
}

.card-contact-button {
  background: var(--button-bg);
  grid-column: 3 / 6;
  grid-row: 15;
  box-sizing: border-box;
  max-width: 100%;
  align-self: center;
  justify-self: center;
  padding: 0 1.2em;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--muted-fg);
  font: inherit;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
  /* Immediate tactile feedback while held; the .is-clicked keyframe pulse below picks up right where this
     leaves off, once released, to confirm the click even on a fast tap. */
  transition: transform 0.1s ease;
}

.card-contact-button:hover {
  border-color: var(--fg);
}

.card-contact-button:active {
  transform: scale(0.92);
}

@keyframes card-contact-button-pulse {
  0% {
    transform: scale(1);
  }
  35% {
    transform: scale(0.9);
    border-color: var(--fg);
  }
  70% {
    transform: scale(1.05);
  }
  100% {
    transform: scale(1);
    border-color: var(--border);
  }
}

.card-contact-button.is-clicked {
  animation: card-contact-button-pulse 0.4s ease;
}

.card-qr-trigger {
  display: block;
  grid-column: 4;
  grid-row: 17;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
}

.card-qr {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Spans almost the whole card (columns 2-6, rows 2-18) purely as an anchor: flexbox pins its one child (the
   enlarged QR) to the bottom, so the empty space above it stays transparent and click-through rather than
   covering the rest of the card. */
.card-qr-overlay {
  grid-column: 2 / 7;
  grid-row: 2 / 19;
  z-index: 5;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  pointer-events: none;
}

.card-qr-overlay-button {
  box-sizing: border-box;
  width: 100%;
  aspect-ratio: 1;
  padding: 0;
  overflow: hidden;
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 0.5rem 1.5rem var(--shadow);
  cursor: pointer;
  /* Collapsed by default, scaling up from roughly where the small QR trigger sits (bottom of the card) rather
     than from the overlay's own center, so growing/shrinking reads as continuous with the small QR. */
  transform: scale(0.05);
  transform-origin: bottom center;
  opacity: 0;
  pointer-events: none;
  transition:
    transform 0.32s ease,
    opacity 0.32s ease;
}

.card-qr-overlay.is-open .card-qr-overlay-button {
  transform: scale(1);
  opacity: 1;
  pointer-events: auto;
}

.card-qr-overlay-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Spans the entire grid (columns 2-6, the full row range) purely as a centering anchor for the actual panel,
   which is 60% of that height — same click-through-outside-the-panel approach as .card-qr-overlay above. */
.card-message-overlay {
  grid-column: 2 / 7;
  grid-row: 1 / 20;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.card-message-panel {
  box-sizing: border-box;
  width: 100%;
  height: 60%;
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: var(--message-gap);
  padding: var(--message-panel-padding);
  background: var(--button-bg);
  border: 1px solid var(--border);
  border-radius: var(--message-panel-radius);
  box-shadow: 0 0.5rem 1.5rem var(--shadow);
  /* Set once here rather than on each of title/editor/button below: all three inherit it (the editor and
     buttons already declare font: inherit; a plain div like the title inherits font-size by default anyway). */
  font-size: var(--message-font-size);
  transform: scale(0.05);
  opacity: 0;
  pointer-events: none;
  transition:
    transform 0.32s ease,
    opacity 0.32s ease;
}

.card-message-overlay.is-open .card-message-panel {
  transform: scale(1);
  opacity: 1;
  pointer-events: auto;
}

.card-message-title {
  color: var(--muted-fg);
  font-weight: 900;
}

.card-message-editor {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  padding: var(--message-editor-padding);
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-radius: var(--message-editor-radius);
  color: var(--editor-fg);
  font: inherit;
  resize: none;
}

.card-message-buttons {
  display: flex;
  justify-content: flex-end;
  gap: var(--message-gap);
}

/* Equal-sized regardless of label length ("Submit" vs "Cancel") since both share this fixed width instead of
   sizing to their own content. Flex items default to min-width: auto, which lets a child's own content force it
   wider than a declared width/flex-basis if the text doesn't fit — overriding that to 0 is what actually makes
   the shared width stick; white-space/overflow below give it somewhere graceful to go if a future label is too
   long for the button rather than silently re-triggering the same growth. border-radius stays a plain 999px (not
   a variable): it's already a scale-invariant "always fully pill-shaped" value, unlike the sizes above which need
   to track the panel's own scale. */
.card-message-button {
  box-sizing: border-box;
  flex: 0 0 var(--message-button-width);
  min-width: 0;
  overflow: hidden;
  padding: var(--message-button-padding-block) 0;
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--fg);
  font: inherit;
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
  cursor: pointer;
}

.card-message-button:hover:not(:disabled) {
  border-color: var(--fg);
}

.card-message-submit:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Spans the entire grid purely as a centering anchor, same approach as .card-message-overlay above. The spinner
   itself keeps spinning continuously even while hidden (harmless: opacity 0 makes it invisible) so that showing
   it never has to wait for an animation to "catch up" from a standstill. */
.card-waiting-overlay {
  grid-column: 2 / 7;
  grid-row: 1 / 20;
  z-index: 15;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.card-spinner {
  box-sizing: border-box;
  width: 12vw;
  height: 12vw;
  max-width: 3rem;
  max-height: 3rem;
  border: 0.35em solid var(--border);
  border-top-color: var(--fg);
  border-radius: 50%;
  opacity: 0;
  transition: opacity 0.2s ease;
  animation: card-spinner-spin 0.8s linear infinite;
}

.card-waiting-overlay.is-open .card-spinner {
  opacity: 1;
}

@keyframes card-spinner-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Same centering-anchor-plus-scaled-panel structure as .card-message-overlay/.card-message-panel; reuses the
   same sizing variables so it stays visually consistent with the message editor it follows in the flow. */
.card-result-overlay {
  grid-column: 2 / 7;
  grid-row: 1 / 20;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.card-result-panel {
  box-sizing: border-box;
  width: 100%;
  height: 60%;
  display: grid;
  grid-template-rows: 1fr auto;
  gap: var(--message-gap);
  padding: var(--message-panel-padding);
  background: var(--button-bg);
  border: 1px solid var(--border);
  border-radius: var(--message-panel-radius);
  box-shadow: 0 0.5rem 1.5rem var(--shadow);
  font-size: var(--message-font-size);
  transform: scale(0.05);
  opacity: 0;
  pointer-events: none;
  transition:
    transform 0.32s ease,
    opacity 0.32s ease;
}

.card-result-overlay.is-open .card-result-panel {
  transform: scale(1);
  opacity: 1;
  pointer-events: auto;
}

.card-result-content {
  overflow-y: auto;
  color: var(--editor-fg);
  white-space: pre-wrap;
  word-break: break-word;
}

/* Diagnostic text tends to be longer and more technical than the plain success message, so it reads better
   smaller and monospaced. */
.card-result-content.is-error {
  font-size: 0.6em;
  font-family: ui-monospace, "SFMono-Regular", Consolas, monospace;
}

.card-result-ok {
  justify-self: end;
  width: 10vw;
}
