/* Wave 3: the creator's page.

   Loads after hub.css and the wave 2 files (Propshaft includes the folder
   alphabetically), so a rule here wins over the same selector there. Tokens
   come from hub.css :root; nothing is redefined. Five parts:

   1. Canvas and type. The lilac gradient without `fixed`, body at 15px,
      script and contract at 16px, nothing under 13px, solid forest on lilac.
   2. Task first. The one sentence under the stepper, the task card's entrance,
      the timeline folded under it.
   3. The agreement: table of contents, sign block, reading bar hand-off,
      the locked button, the finger pad, a refusal next to the button.
   4. The upload: a real picker, clip rows, progress inside the lime button.
   5. The moment on the stepper, WhatsApp first, bank details, home screen. */

/* ---------- 1. Canvas and type ---------- */

/* Top-anchored: the gradient runs over the first 900px and settles into the
   solid lilac for the rest of a long page. `fixed` was not honoured on iOS
   and stretched the gradient over 4800px of agreement. */
body.portal-page {
  background-color: #D2BFFB;
  background-image: linear-gradient(170deg, #DACEFD 0px, #D2BFFB 900px, #D2BFFB 100%);
  background-attachment: scroll;
  background-repeat: no-repeat;
  font-size: 15px;
  line-height: 1.6;
}

.portal-page .page-sub,
.portal-page .field-hint,
.portal-page .portal-upload-status,
.portal-page .portal-timeline-when,
.portal-page .portal-clip-meta,
.portal-page .portal-sign-note {
  font-size: 13.5px;
}

/* Secondary text on the lilac canvas in solid forest: the alpha tints were
   under AA there. On white cards the softer tone is enough. */
.portal-page .page-sub,
.portal-page .portal-foot,
.portal-page .portal-step-caption {
  color: rgba(12, 65, 41, .85);
}

.portal-page .card .page-sub,
.portal-page .card .field-hint {
  color: var(--ink-soft);
}

.portal-foot {
  font-size: 13.5px;
  color: var(--ink);
}

.portal-steps li {
  color: rgba(12, 65, 41, .7);
  font-size: 13px;
}

.portal-steps li.done,
.portal-steps li.current {
  color: var(--ink);
}

.portal-script {
  font-size: 16px;
  line-height: 1.7;
}

.portal-contract {
  font-size: 15px;
  line-height: 1.7;
}

.portal-check {
  font-size: 15px;
  line-height: 1.8;
}

.portal-details summary {
  font-size: 15px;
}

.portal-main .btn-sm {
  min-height: 44px;
}

@media (min-width: 761px) {
  .portal-contract {
    font-size: 16px;
  }
}

/* ---------- 2. Task first ---------- */

/* Which step, in one line under the circles. */
.portal-step-caption {
  text-align: center;
  margin: -8px 0 0;
  font-size: 13.5px;
  font-weight: 600;
}

/* The task, as a sentence. The first thing she reads after her name. */
.portal-task {
  text-align: center;
  font-size: 18px;
  line-height: 1.4;
  font-weight: 700;
  color: var(--ink);
  margin: 14px auto 6px;
  max-width: 30ch;
  text-wrap: balance;
}

/* One entrance, on the task card only: "this is yours". */
@media (prefers-reduced-motion: no-preference) {
  .portal-task-card {
    animation: portal-card-in var(--dur-slow) var(--ease-out) both;
  }

  @keyframes portal-card-in {
    from { opacity: 0; transform: translateY(8px); filter: blur(3px); }
    to { opacity: 1; transform: translateY(0); filter: blur(0); }
  }
}

/* The six rows, folded. A summary row is a 44px target with a chevron that
   turns as it opens; the rows grow in on the house curve (.reveal). */
.portal-timeline-fold .portal-details {
  margin-top: 0;
}

.portal-timeline-fold .portal-details summary {
  padding: 2px 0;
}

.portal-details summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 44px;
  padding: 12px 0;
  cursor: pointer;
  font-weight: 700;
}

.portal-details summary::-webkit-details-marker {
  display: none;
}

.portal-details summary::after {
  content: "›";
  flex: 0 0 auto;
  font-size: 22px;
  line-height: 1;
  color: var(--ink-soft);
  transition: transform var(--dur-enter) var(--ease-out);
}

.portal-details[open] summary::after {
  transform: rotate(90deg);
}

.portal-timeline li.skipped .portal-timeline-dot {
  background: rgba(12, 65, 41, .18);
  border-color: transparent;
}

/* The box keeps a card of its own only when there is a tracking link to tap. */
.portal-box-card h2 {
  font-size: var(--fs-title);
}

/* ---------- 3. The agreement ---------- */

.portal-contract-estimate {
  margin: -2px 0 12px;
}

/* A short table of contents at the top of the text, jump links. */
.portal-contract-toc {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 4px 14px;
  margin: 0 0 18px;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  background: rgba(12, 65, 41, .05);
  font-size: 13.5px;
  line-height: 1.5;
}

.portal-contract-toc a {
  color: var(--ink);
  font-weight: 600;
  text-decoration: none;
  min-height: 32px;
  display: flex;
  align-items: center;
}

.portal-contract-toc a:hover {
  text-decoration: underline;
}

.portal-contract-heading {
  font-weight: 700;
  scroll-margin-top: 16px;
}

/* The sign block: name first, pad second, one line of law above the button. */
.portal-sign-terms {
  margin-bottom: 18px;
}

.portal-sign .field {
  margin-bottom: 16px;
}

.portal-sign-note {
  margin: 0 0 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}

.portal-sign-record {
  margin: 14px 0 0;
  font-weight: 500;
  font-size: 13.5px;
  color: var(--ink-soft);
}

/* Reading bar hand-off: the colour change glides and the arrow turns to
   point at the sign block once the end has been seen. */
.portal-readbar {
  transition: background var(--dur-slow) var(--ease-out), color var(--dur-slow) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

.portal-readbar:active {
  transform: scale(.98);
}

.portal-readbar-arrow {
  display: inline-block;
  transition: transform var(--dur-slow) var(--ease-out);
}

.portal-readbar.is-ready .portal-readbar-arrow {
  transform: rotate(90deg);
}

/* Locked buttons say why and still answer a tap, so they are dimmed less
   than a disabled control and keep the pointer. */
.portal-main .btn[aria-disabled="true"] {
  opacity: .6;
  cursor: pointer;
}

/* The finger pad: the hint fades on the first stroke, the border goes solid. */
.sign-pad {
  transition: border-color var(--dur-base) var(--ease-out);
}

.sign-pad.is-dirty {
  border: 1px solid var(--ink);
}

.sign-pad-hint {
  font-size: 14px;
  color: var(--ink-faint);
  transition: opacity var(--dur-base) var(--ease-out);
}

.sign-pad-hint.is-hidden {
  opacity: 0;
}

/* A refusal rendered inside the card, next to the button. */
.portal-flash-inline {
  margin: 0 0 12px;
  font-size: 14px;
}

/* Who is asking for her ID, at the moment she is asked. */
.portal-trust {
  margin: -4px 0 12px;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  background: rgba(12, 65, 41, .05);
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink);
}

/* ---------- 4. The upload ---------- */

/* The native control, kept for the form and the screen reader, off screen. */
.portal-file-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.portal-file-input:focus-visible + .portal-picker {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.portal-picker {
  display: flex;
  width: 100%;
  min-height: 48px;
  margin-bottom: 10px;
  cursor: pointer;
}

.portal-size-line {
  margin-top: 0;
}

.portal-size-line a {
  color: var(--ink);
  font-weight: 600;
}

/* Two chips, raw already chosen. The radio stays inside the label. */
.portal-choice {
  flex-direction: row;
  flex-wrap: wrap;
  gap: 8px;
}

.portal-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 16px;
  border-radius: var(--r-pill);
  border: 1.5px solid var(--line-strong);
  background: var(--surface-solid);
  font-weight: 600;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

.portal-chip:active {
  transform: scale(.98);
}

.portal-chip:has(:checked) {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--lime);
}

.portal-chip input {
  margin: 0;
  width: 14px;
  height: 14px;
  accent-color: var(--lime);
}

.portal-chip:has(:focus-visible) {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* Her clips as rows, one after another, each ticked as it lands. */
.portal-queue {
  margin: 4px 0 0;
}

.portal-queue li {
  align-items: center;
}

.portal-queue .portal-clip-check {
  opacity: .25;
  transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-slow) var(--ease-pop);
}

.portal-queue li.is-sent .portal-clip-check {
  opacity: 1;
  transform: scale(1.15);
}

/* Progress inside the lime button: a lime-deep fill from the left, the
   label over it, a slow sheen while it works. */
.portal-send {
  --progress: 0%;
  background-image: linear-gradient(180deg, var(--lime), var(--lime-deep));
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out), background-size 250ms var(--ease-out);
}

.portal-send.is-uploading {
  opacity: 1;
  cursor: progress;
  background-color: var(--lime);
  background-image:
    linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, .5) 50%, transparent 70%),
    linear-gradient(var(--lime-deep), var(--lime-deep));
  background-size: 220% 100%, var(--progress) 100%;
  background-repeat: no-repeat;
  animation: btn-shimmer 1.8s var(--ease-in-out) infinite;
}

.portal-send.is-uploading:hover {
  background-color: var(--lime);
  color: var(--lime-ink);
}

.portal-upload-status strong {
  font-size: 14px;
  color: var(--ink);
}

/* The first frame, centred, small, and arriving rather than appearing. */
.portal-poster {
  width: 160px;
  max-width: 100%;
  margin: 12px auto 4px;
}

@media (prefers-reduced-motion: no-preference) {
  .portal-poster:not([hidden]),
  .portal-queue li {
    animation: portal-blur-in var(--dur-enter) var(--ease-out) both;
  }

  .portal-queue li {
    animation-delay: calc(var(--i, 0) * 40ms);
  }

  @keyframes portal-blur-in {
    from { opacity: 0; transform: translateY(6px); filter: blur(2px); }
    to { opacity: 1; transform: translateY(0); filter: blur(0); }
  }
}

/* ---------- 5. The moment, WhatsApp, bank, home screen ---------- */

/* The page steps back while the stepper does its thing. The moment's own
   element is the line under the steps; the circles are the show. */
.portal-main > *:not(.portal-steps):not(.portal-moment):not(.portal-hello):not(.portal-logo),
.portal-foot {
  transition: opacity var(--dur-slow) var(--ease-out);
}

body.is-moment .portal-main > *:not(.portal-steps):not(.portal-moment):not(.portal-hello):not(.portal-logo),
body.is-moment .portal-foot {
  opacity: .3;
}

.portal-steps li span {
  transition: background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out);
}

/* hub.css styles .portal-moment as the old dialog (white box, shadow); here
   it is a line of text under the steps and nothing else. */
.portal-moment {
  width: auto;
  background: none;
  box-shadow: none;
  border-radius: 0;
  margin: -6px 0 14px;
  text-align: center;
}

.portal-moment-title {
  margin: 0;
  font-weight: 700;
  font-size: 19px;
  line-height: 1.35;
  color: var(--ink);
  text-wrap: balance;
}

/* Live means the script is driving: the line waits for the tick to flip,
   then blurs in. Without the script it is simply there. */
.portal-moment.is-live .portal-moment-title {
  opacity: 0;
  transition: opacity var(--dur-enter) var(--ease-out), transform var(--dur-enter) var(--ease-out),
              filter var(--dur-enter) var(--ease-out);
}

.portal-moment.is-live.is-titled .portal-moment-title {
  opacity: 1;
}

@media (prefers-reduced-motion: no-preference) {
  .portal-moment.is-live .portal-moment-title {
    transform: translateY(6px);
    filter: blur(3px);
  }

  .portal-moment.is-live.is-titled .portal-moment-title {
    transform: translateY(0);
    filter: blur(0);
  }

  .portal-steps li.is-flipping span {
    animation: portal-flip var(--dur-slow) var(--ease-pop);
  }

  .portal-steps li.is-lighting span {
    animation: portal-light var(--dur-slow) var(--ease-pop);
  }

  @keyframes portal-flip {
    0% { transform: scale(1); }
    50% { transform: scale(1.12); }
    100% { transform: scale(1); }
  }

  @keyframes portal-light {
    0% { transform: scale(1); }
    50% { transform: scale(1.08); }
    100% { transform: scale(1); }
  }
}

/* WhatsApp first, the form second. */
.portal-whatsapp {
  margin-bottom: 4px;
}

/* The IBAN on file, masked, in figures that line up. */
.portal-iban-mask {
  font-variant-numeric: var(--num);
  white-space: nowrap;
}

.field-hint.is-short {
  color: var(--warn-ink);
}

.field-hint.is-complete {
  color: var(--ok-ink);
}

/* Keep this page on your phone: a small card above the home indicator. */
.portal-homescreen {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: calc(16px + var(--safe-b));
  z-index: var(--z-toast);
  max-width: 560px;
  margin: 0 auto;
  padding: 14px 16px;
  border-radius: var(--r);
  background: var(--surface-solid);
  box-shadow: var(--shadow-sheet);
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 14px;
  line-height: 1.5;
}

.portal-homescreen p {
  margin: 0;
  flex: 1 1 auto;
}

@media (prefers-reduced-motion: no-preference) {
  .portal-homescreen:not([hidden]) {
    animation: portal-blur-in var(--dur-enter) var(--ease-out) both;
  }
}
