/* GCP Business OS — bank statement console.
 *
 * Pink/purple/white. Mobile-first: the base rules are the phone layout and
 * media queries add the desktop one, because Juhi will often be checking a
 * statement from a phone rather than a desk.
 *
 * Status colours are reserved (matched / review / suspense) and never reused
 * for decoration. Every status is paired with a text label — colour alone is
 * not an accessible signal, and "which of these two pinks means a problem" is
 * not something an operator should have to remember.
 */

:root {
  --purple-700: #6b21a8;
  --purple-600: #7c3aed;
  --purple-500: #8b5cf6;
  --purple-100: #ede9fe;
  --purple-050: #faf5ff;

  --pink-600: #db2777;
  --pink-500: #ec4899;
  --pink-100: #fce7f3;

  --ink:        #1f2937;
  --ink-muted:  #6b7280;
  --ink-subtle: #9ca3af;

  --surface:      #ffffff;
  --surface-alt:  #faf7ff;
  --border:       #e9d8fd;
  --border-soft:  #f1e8fd;

  /* Reserved status palette. Not for decoration. */
  --ok:        #15803d;
  --ok-bg:     #dcfce7;
  --warn:      #b45309;
  --warn-bg:   #fef3c7;
  --alert:     #b91c1c;
  --alert-bg:  #fee2e2;
  --info:      #6b21a8;
  --info-bg:   #ede9fe;

  --radius: 14px;
  --radius-sm: 9px;
  --shadow: 0 1px 2px rgba(76, 29, 149, 0.06), 0 8px 24px rgba(76, 29, 149, 0.07);
  --gradient: linear-gradient(135deg, var(--pink-500) 0%, var(--purple-600) 100%);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  background: var(--purple-050);
  color: var(--ink);
  line-height: 1.5;
  font-size: 15px;
}

/* --- layout ------------------------------------------------------------ */

.app-header {
  background: var(--gradient);
  color: #fff;
  padding: 18px 16px;
}

.header-inner {
  max-width: 1180px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.brand { display: flex; align-items: center; gap: 11px; }

.brand-mark {
  width: 38px; height: 38px;
  border-radius: 11px;
  background: rgba(255, 255, 255, 0.2);
  display: grid; place-items: center;
  font-weight: 700; font-size: 15px;
  border: 1px solid rgba(255, 255, 255, 0.3);
  flex-shrink: 0;
}

/* min-width:0 opts the brand out of the flex "never shrink below content" floor,
   so when the header runs short of room the page title ellipsizes instead of
   shouldering the other items sideways. */
.brand-text { min-width: 0; }
.brand-text h1 { margin: 0; font-size: 17px; font-weight: 650; letter-spacing: -0.01em; }
.brand-text p  { margin: 1px 0 0; font-size: 12.5px; opacity: 0.85; }
.brand-text h1,
.brand-text p { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- section navigation ------------------------------------------------- */

.app-nav { display: flex; gap: 6px; }

.nav-link {
  padding: 7px 13px;
  border-radius: 999px;
  font-size: 13.5px;
  font-weight: 600;
  color: #fff;
  text-decoration: none;
  border: 1px solid rgba(255, 255, 255, 0.3);
  background: rgba(255, 255, 255, 0.12);
  white-space: nowrap;
}
.nav-link:hover { background: rgba(255, 255, 255, 0.22); }

/* The current section is filled rather than merely tinted. On the purple header
   two translucent pills at slightly different opacities are not a difference
   anyone reads as "you are here". */
.nav-link.is-current {
  background: #fff;
  color: var(--purple-700);
  border-color: #fff;
}

/* --- master data --------------------------------------------------------- */

.tabs {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  /* Four tabs do not fit a phone. Scrolling the strip keeps them all reachable
     without wrapping into a second row that pushes the list off screen. */
  -webkit-overflow-scrolling: touch;
  padding-bottom: 2px;
}

.tab {
  flex: none;
  padding: 9px 15px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink-muted);
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  min-height: 40px;
}
.tab:hover { border-color: var(--purple-500); }
.tab.is-current {
  background: var(--gradient);
  border-color: transparent;
  color: #fff;
}

.toolbar {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 14px;
}
.toolbar-search { flex: 1; }
.toolbar-actions { display: flex; flex-wrap: wrap; gap: 8px; }
/* An anchor styled as a button needs the line-height put back. */
.toolbar-actions .btn { text-decoration: none; display: inline-flex; }

.mrow-list { display: flex; flex-direction: column; gap: 10px; }

.mrow {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm);
  padding: 12px 13px;
  background: var(--surface);
}

.mrow-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}
.mrow-name { font-weight: 650; font-size: 14.5px; overflow-wrap: anywhere; }
.mrow-sub { font-size: 12.5px; color: var(--ink-muted); margin-top: 2px; overflow-wrap: anywhere; }
.mrow-value { font-weight: 700; font-size: 14.5px; white-space: nowrap; }

.mrow-meta { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px; }
.mrow-meta:empty { margin-top: 0; }

.add-form {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-alt);
  padding: 14px;
  margin-bottom: 14px;
}
.add-form h3 { margin: 0 0 12px; font-size: 15px; }
.add-fields { display: grid; gap: 12px; }
.add-actions { display: flex; gap: 8px; margin-top: 14px; }

.field-hint { margin: 3px 0 0; font-size: 11.5px; color: var(--ink-subtle); }

/* Import problems. Deliberately a plain list of "row, column, what is wrong"
   rather than a table: the person reading it is going back to Excel to fix
   named rows, and a table of one-line reasons is harder to scan than the
   reasons themselves. */
.issue-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 10px;
  max-height: 320px;
  overflow-y: auto;
}
.issue {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  font-size: 13px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--alert-bg);
  color: var(--ink);
}
.issue-where { font-weight: 700; color: var(--alert); white-space: nowrap; }

/* Bill detail under each party. A list of lines rather than a real table:
   these are read on a phone as often as a desk, and a four-column table at
   360px is a horizontal scroll nobody performs. */
.bill-table {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 10px;
  padding-top: 9px;
  border-top: 1px dashed var(--border);
}
.bill-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  font-size: 12.5px;
}
.bill-ref { font-weight: 600; overflow-wrap: anywhere; }
.bill-age { color: var(--ink-muted); }
.bill-amount { margin-left: auto; font-weight: 650; white-space: nowrap; }
.bill-part { color: var(--ok); }

/* --- company logos ------------------------------------------------------ */

/* The supplied logos are opaque and disagree about their background — two are
   white, one is black — so none of them can sit directly on the purple header
   or on the white card without one of the three looking broken. A tile gives
   every logo the same neutral ground, which is also what keeps a future
   fourth company from needing its own special case. */
.logo-tile {
  background: #fff;
  border-radius: var(--radius-sm);
  display: grid;
  place-items: center;
  flex-shrink: 0;
  overflow: hidden;
}
/* `hidden` must win over the grid display, or the empty tile shows anyway. */
.logo-tile[hidden] { display: none; }

.logo-tile img {
  display: block;
  width: auto;
  /* Logos range from square to 2.4:1. Fixing the height and letting width
     follow keeps them optically similar without distorting any of them. */
  object-fit: contain;
}

.brand .logo-tile {
  height: 38px;
  padding: 4px 7px;
  border: 1px solid rgba(255, 255, 255, 0.35);
}
.brand .logo-tile img { height: 26px; max-width: 104px; }

.entity-picker { display: flex; align-items: center; gap: 8px; }
.entity-picker label { font-size: 12.5px; opacity: 0.9; white-space: nowrap; }

.entity-picker select {
  flex: 1;
  min-width: 0;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  font-size: 14px;
  font-family: inherit;
}
.entity-picker select option { color: var(--ink); }

main {
  max-width: 1180px;
  margin: 0 auto;
  padding: 16px 16px 64px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* --- cards ------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.card-head {
  padding: 14px 16px;
  border-bottom: 1px solid var(--border-soft);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.card-head h2 {
  margin: 0;
  font-size: 15px;
  font-weight: 640;
  display: flex;
  align-items: center;
  gap: 8px;
}

.card-head .step {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--gradient);
  color: #fff;
  display: grid; place-items: center;
  font-size: 11.5px; font-weight: 700;
  flex-shrink: 0;
}

.card-body { padding: 16px; }
.card-hint { margin: 0 0 12px; font-size: 13px; color: var(--ink-muted); }

/* --- upload ------------------------------------------------------------ */

.dropzone {
  border: 2px dashed var(--border);
  border-radius: var(--radius);
  background: var(--surface-alt);
  padding: 26px 16px;
  text-align: center;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.dropzone:hover, .dropzone:focus-visible { border-color: var(--purple-500); }
.dropzone.dragging { border-color: var(--pink-500); background: var(--pink-100); }
.dropzone[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }

.dropzone-icon { font-size: 27px; }
.dropzone-title { font-weight: 620; margin: 8px 0 3px; font-size: 14.5px; }
.dropzone-sub { font-size: 12.5px; color: var(--ink-muted); }

/* --- buttons ----------------------------------------------------------- */

.btn {
  appearance: none;
  border: 0;
  border-radius: var(--radius-sm);
  padding: 11px 17px;
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  /* Comfortable thumb target on a phone. */
  min-height: 44px;
}
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-primary { background: var(--gradient); color: #fff; }
.btn-primary:hover:not(:disabled) { filter: brightness(1.06); }

.btn-secondary {
  background: var(--purple-100);
  color: var(--purple-700);
  border: 1px solid var(--border);
}
.btn-secondary:hover:not(:disabled) { background: var(--border); }

.btn-ghost {
  background: transparent;
  color: var(--purple-700);
  border: 1px solid var(--border);
}

.btn-sm { padding: 7px 12px; font-size: 13px; min-height: 38px; }
.btn-block { width: 100%; }

/* --- stat tiles -------------------------------------------------------- */

/* Counts, not a chart: five single numbers have no shape worth plotting. */
.stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}

.stat {
  background: var(--surface-alt);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm);
  padding: 12px;
}
.stat-value { font-size: 23px; font-weight: 700; line-height: 1.15; letter-spacing: -0.02em; }
.stat-label { font-size: 11.5px; color: var(--ink-muted); margin-top: 2px; }

.stat.is-ok    .stat-value { color: var(--ok); }
.stat.is-warn  .stat-value { color: var(--warn); }
.stat.is-alert .stat-value { color: var(--alert); }
.stat.is-info  .stat-value { color: var(--info); }

/* --- status pills ------------------------------------------------------ */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  white-space: nowrap;
}
.pill-ok     { background: var(--ok-bg);    color: var(--ok); }
.pill-warn   { background: var(--warn-bg);  color: var(--warn); }
.pill-alert  { background: var(--alert-bg); color: var(--alert); }
.pill-info   { background: var(--info-bg);  color: var(--info); }
.pill-muted  { background: #f3f4f6;         color: var(--ink-muted); }

/* --- transactions ------------------------------------------------------ */

.txn-list { display: flex; flex-direction: column; gap: 10px; }

.txn {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm);
  padding: 12px;
  background: var(--surface);
}
.txn.needs-attention { border-left: 3px solid var(--pink-500); }

.txn-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 5px;
}
.txn-date { font-size: 12.5px; color: var(--ink-muted); }

.txn-amount { font-weight: 700; font-size: 15px; white-space: nowrap; }
.txn-amount.credit { color: var(--ok); }
.txn-amount.debit  { color: var(--ink); }

.txn-narration {
  font-size: 13px;
  color: var(--ink);
  word-break: break-word;
  margin-bottom: 7px;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  line-height: 1.45;
}

.txn-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  font-size: 12.5px;
  color: var(--ink-muted);
}

.txn-assign {
  margin-top: 11px;
  padding-top: 11px;
  border-top: 1px dashed var(--border);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.field { display: flex; flex-direction: column; gap: 4px; }
.field label { font-size: 11.5px; font-weight: 600; color: var(--ink-muted); }

select, input[type="text"], input[type="password"] {
  width: 100%;
  padding: 10px 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-family: inherit;
  background: var(--surface);
  color: var(--ink);
  min-height: 44px;
}
select:focus, input:focus, .dropzone:focus-visible, .btn:focus-visible {
  outline: 2px solid var(--purple-500);
  outline-offset: 1px;
}

.assign-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.assign-actions .btn { flex: 1; }

/* Password prompt for an encrypted statement. Sits between the dropzone and
   the progress bar, so the next action is where the eye already is. */
.password-prompt {
  margin-top: 12px;
  padding: 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--warn-bg);
}
.password-prompt .card-hint { margin: 8px 0 11px; }

/* --- misc -------------------------------------------------------------- */

.banner {
  padding: 11px 13px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  margin-bottom: 12px;
  display: flex;
  gap: 9px;
  align-items: flex-start;
}
.banner-ok    { background: var(--ok-bg);    color: var(--ok); }
.banner-warn  { background: var(--warn-bg);  color: var(--warn); }
.banner-alert { background: var(--alert-bg); color: var(--alert); }
.banner-info  { background: var(--info-bg);  color: var(--info); }
.banner strong { font-weight: 680; }

.empty {
  text-align: center;
  padding: 30px 16px;
  color: var(--ink-subtle);
  font-size: 13.5px;
}
.empty-icon { font-size: 30px; display: block; margin-bottom: 7px; opacity: 0.6; }

.spinner {
  width: 17px; height: 17px;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.progress {
  height: 4px;
  background: var(--purple-100);
  border-radius: 999px;
  overflow: hidden;
  margin-top: 12px;
}
.progress-bar {
  height: 100%;
  background: var(--gradient);
  width: 30%;
  animation: slide 1.15s ease-in-out infinite;
}
@keyframes slide {
  0%   { margin-left: -30%; }
  100% { margin-left: 100%; }
}

.export-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 11px 0;
  border-bottom: 1px solid var(--border-soft);
  flex-wrap: wrap;
}
.export-item:last-child { border-bottom: 0; }
.export-name { font-weight: 600; font-size: 13.5px; word-break: break-all; }
.export-meta { font-size: 12px; color: var(--ink-muted); }

.filters { display: flex; gap: 7px; flex-wrap: wrap; }

.chip {
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-muted);
  cursor: pointer;
  font-family: inherit;
  min-height: 36px;
}
.chip[aria-pressed="true"] {
  background: var(--gradient);
  color: #fff;
  border-color: transparent;
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.toast {
  position: fixed;
  left: 16px; right: 16px; bottom: 16px;
  background: var(--ink);
  color: #fff;
  padding: 13px 15px;
  border-radius: var(--radius-sm);
  font-size: 13.5px;
  box-shadow: var(--shadow);
  z-index: 50;
  animation: rise 0.2s ease-out;
}
.toast.is-error { background: var(--alert); }
@keyframes rise { from { transform: translateY(10px); opacity: 0; } }

/* --- desktop ----------------------------------------------------------- */

@media (min-width: 720px) {
  body { font-size: 15.5px; }
  /* The header is two groups, not four loose items: brand + nav on the left,
     company picker + user chip on the right. The split is done by margin-left
     on the picker, deliberately NOT by justify-content: space-between — with
     flex-wrap on, space-between spreads a half-filled row across the full
     width, which is what let the user chip drift into the picker and nav.

     Every header rule for this breakpoint lives here. There was a second
     @media (min-width: 720px) further down the file that also set
     .header-inner; two blocks 270 lines apart silently fought each other. */
  .header-inner {
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    column-gap: 18px;
    row-gap: 10px;
  }
  .brand { min-width: 0; }
  .app-nav { flex: 0 0 auto; }
  .entity-picker { margin-left: auto; min-width: 0; }
  /* Was a hard min-width:290px + flex:none. That floor is what overflowed the
     row on any screen narrower than ~1180px; the select now gives ground
     before the header breaks. */
  .entity-picker select { min-width: 0; width: clamp(190px, 20vw, 290px); flex: 0 1 auto; }
  .user-chip { flex: 0 0 auto; }
  main { padding: 22px 22px 80px; gap: 18px; }
  .stats { grid-template-columns: repeat(5, 1fr); }
  .dropzone { padding: 38px; }
  .card-body { padding: 18px; }

  .txn-assign { flex-direction: row; align-items: flex-end; }
  .txn-assign .field { flex: 1; }
  .assign-actions .btn { flex: none; }
  .toast { left: auto; right: 22px; max-width: 380px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* --- login ------------------------------------------------------------- */

.login-page { background: var(--gradient); min-height: 100vh; }

.login-shell {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 20px 16px;
}

.login-card { width: 100%; max-width: 400px; }

.login-brand {
  text-align: center;
  padding: 26px 20px 18px;
  border-bottom: 1px solid var(--border-soft);
}
.login-brand .brand-mark {
  margin: 0 auto 12px;
  background: var(--gradient);
  color: #fff;
  border: 0;
  width: 46px; height: 46px;
  border-radius: 13px;
  font-size: 16px;
}
.login-brand h1 { margin: 0; font-size: 19px; font-weight: 660; }
.login-brand p  { margin: 3px 0 0; font-size: 12.5px; color: var(--ink-muted); }

.login-logos {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 10px;
  margin-top: 14px;
  /* Three logos side by side are 300px+ wide; the card is 400px at most and
     narrower than that on a phone, which is where this page is usually opened. */
  flex-wrap: wrap;
}
.login-logos .logo-tile {
  height: 44px;
  padding: 6px 9px;
  border: 1px solid var(--border);
}
.login-logos img { height: 30px; max-width: 104px; }

/* --- form and card spacing ---------------------------------------------- */

/* These live here rather than as style="" attributes on the elements. The
   pages are served with `style-src 'self'` and no `unsafe-inline`, which blocks
   inline style attributes outright — so every one of these margins was being
   dropped on the floor in production while looking perfectly correct in the
   markup. Expressed as relationships between elements, they also survive
   someone adding a third field without remembering to copy a margin across. */

.field + .field { margin-top: 12px; }
.field + .card-hint { margin-top: 8px; }
form .btn-block { margin-top: 16px; }

#upload-status { margin-top: 10px; }
#txn-container { margin-top: 14px; }
#export-list { margin-top: 14px; }
.export-note { margin: 10px 0 0; }

/* --- opening splash ----------------------------------------------------- */

/* Timeline — 3.9s end to end. Every number below is one of these:
 *
 *   0.05 → 0.75   G arrives from the left
 *   0.15 → 0.85   C drops in from above
 *   0.25 → 0.95   P arrives from the right
 *   0.70 → 1.10   "Great Companies & People" fades up
 *   2.60 → 2.90   ...and fades out again  (a 1.50s hold, as specified)
 *   2.85 → 3.15   "cloud" resolves in its place
 *   3.18 → 3.46   ".in" completes the wordmark
 *   3.45 → 3.90   the whole splash fades away
 *
 * No script anywhere: the last keyframe lands on visibility:hidden, which also
 * removes the overlay from hit-testing, so the form beneath becomes usable on
 * its own. Anything JS-driven would have to survive a failed fetch, a slow
 * parse and the CSP — a fade that cannot get stuck is worth more than that.
 */

/* Second and later visits in the same browser session. `display: none` rather
   than an opacity trick, so the animations never start and the overlay is never
   in the layer at all — a returning user who signs out and back in should meet
   the form, not a title sequence. splash.js sets the class in <head>. */
.splash-seen .splash { display: none; }

.splash {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  /* Letters start up to 46vw off-screen; without this they would widen the
     document and put a scrollbar on the page for the first second. */
  overflow: hidden;
  background: radial-gradient(
    120% 90% at 50% 42%,
    #2a1152 0%,
    #150a2b 45%,
    #0a0616 100%
  );
  animation: splash-exit 0.45s ease-in 3.45s both;
}

.splash-lockup { text-align: center; padding: 0 16px; }

.splash-wordmark {
  display: flex;
  justify-content: center;
  /* Baselines, not boxes: the small suffix has to sit on the same line the
     capitals stand on, or "GCPcloud.in" reads as two separate things. */
  align-items: baseline;
  line-height: 1;
  font-size: clamp(56px, 18vw, 116px);
  color: #fff;
}

.splash-letter {
  display: inline-block;
  letter-spacing: 0.06em;
  font-weight: 750;
  text-shadow: 0 0 38px rgba(168, 85, 247, 0.55), 0 0 90px rgba(236, 72, 153, 0.3);
  animation-duration: 0.7s;
  /* Decelerating hard at the end — the letters arrive and settle rather than
     coasting to a stop, which is what makes three of them land as one word. */
  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
  animation-fill-mode: both;
}
/* letter-spacing leaves a gap after the final capital. Reclaiming it is what
   closes "GCP" up against "cloud" so the five parts read as one wordmark
   rather than as a name with something appended. */
.splash-p { margin-right: -0.06em; }

.splash-g { animation-name: splash-from-left; animation-delay: 0.05s; }
.splash-c { animation-name: splash-from-top; animation-delay: 0.15s; }
.splash-p { animation-name: splash-from-right; animation-delay: 0.25s; }

@keyframes splash-from-left {
  from { opacity: 0; transform: translate3d(-46vw, 0, 0) rotate(-14deg); filter: blur(7px); }
  to   { opacity: 1; transform: translate3d(0, 0, 0) rotate(0deg); filter: blur(0); }
}
@keyframes splash-from-top {
  from { opacity: 0; transform: translate3d(0, -52vh, 0) rotate(9deg); filter: blur(7px); }
  to   { opacity: 1; transform: translate3d(0, 0, 0) rotate(0deg); filter: blur(0); }
}
@keyframes splash-from-right {
  from { opacity: 0; transform: translate3d(46vw, 0, 0) rotate(14deg); filter: blur(7px); }
  to   { opacity: 1; transform: translate3d(0, 0, 0) rotate(0deg); filter: blur(0); }
}

.splash-tagline {
  margin: 20px 0 0;
  text-transform: uppercase;
  letter-spacing: 0.34em;
  /* Balances that same trailing letter-space, on a line where it is wide
     enough to be visible. */
  text-indent: 0.34em;
  font-size: clamp(9.5px, 2.7vw, 13px);
  font-weight: 400;
  color: rgba(255, 255, 255, 0.82);
  animation:
    splash-rise 0.4s ease-out 0.7s both,
    splash-fade 0.3s ease-in 2.6s forwards;
}

/* Sized in `em`, so the suffix tracks the capitals through the whole clamp
   range instead of needing its own breakpoints. */
.splash-cloud,
.splash-in {
  display: inline-block;
  font-size: 0.2em;
  font-weight: 300;
  letter-spacing: 0.02em;
}
.splash-cloud {
  color: rgba(255, 255, 255, 0.9);
  animation: splash-resolve 0.3s ease-out 2.85s both;
}
.splash-in {
  color: var(--pink-500);
  animation: splash-resolve 0.28s ease-out 3.18s both;
}

@keyframes splash-rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@keyframes splash-fade { to { opacity: 0; } }
@keyframes splash-resolve {
  from { opacity: 0; transform: translateY(6px); filter: blur(4px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

/* visibility is a discrete property: interpolated across the whole fade it
   would flip at the halfway point and snap the splash away mid-dissolve. The
   99% stop pins the switch to the very end. */
@keyframes splash-exit {
  0%   { opacity: 1; visibility: visible; }
  99%  { visibility: visible; }
  100% { opacity: 0; visibility: hidden; }
}

/* Flying, blurring type is exactly what this setting is asking us not to do.
   The wordmark still shows — briefly, and already assembled — so the brand
   moment survives without the motion. */
@media (prefers-reduced-motion: reduce) {
  .splash-letter,
  .splash-cloud,
  .splash-in {
    animation: none;
    opacity: 1;
    transform: none;
    filter: none;
  }
  .splash-tagline { display: none; }
  .splash { animation: splash-exit 0.4s ease-in 1.1s both; }
}

/* --- signed-in user chip in the header --------------------------------- */

.user-chip {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 12.5px;
}
/* The name and the Sign out button stay on one line and are never compressed.
   A long full name ellipsizes rather than wrapping under the button or pushing
   the button out of the header. */
.user-chip .who {
  opacity: 0.9;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 22ch;
}
.user-chip button { flex-shrink: 0; }
.user-chip button {
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.32);
  color: #fff;
  border-radius: 999px;
  padding: 5px 12px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  min-height: 32px;
}
.user-chip button:hover { background: rgba(255, 255, 255, 0.26); }

@media (min-width: 720px) {
  /* .header-inner used to be styled here too — moved up into the single header
     block in the desktop section so all of its rules sit together. */
  .toolbar { flex-direction: row; align-items: flex-end; }
  .toolbar-actions { margin-left: auto; }
  /* Two columns of form fields once there is room; the add forms run to eight
     fields and a single column turns that into a scroll. */
  .add-fields { grid-template-columns: 1fr 1fr; }
}
