* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  min-height: 100%;
}

body {
  font-family: "Helvetica Now Display", "Helvetica Neue", Arial, sans-serif;
}

#app[data-theme="light"] {
  --dulcedo-page-bg: #f4f4f4;
  --dulcedo-card-bg: #ffffff;
  --dulcedo-text: #0a0a0a;
  --dulcedo-muted: #6b6b66;
  --dulcedo-border: #dedede;
}

#app[data-theme="dark"] {
  --dulcedo-page-bg: #0a0a0a;
  --dulcedo-card-bg: #141414;
  --dulcedo-text: #ffffff;
  --dulcedo-muted: #cccccc;
  --dulcedo-border: #393939;
}

#app {
  --dulcedo-gold: #c5ae79;
  --dulcedo-gold-dark: #7c735c;
  min-height: 100vh;
}

.topbar {
  background: #0a0a0a;
  padding: 16px 28px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.topbar .brand {
  display: inline-flex;
  align-items: center;
  line-height: 0;
}

.brand-logo {
  /* Logo includes the circle mark stacked above the wordmark, so it needs
     more height than the old 22px text to read at the same visual weight. */
  height: 48px;
  width: auto;
  display: block;
}

.theme-toggle {
  background: transparent;
  border: 0.5px solid var(--dulcedo-gold-dark);
  border-radius: 1000px;
  width: 30px;
  height: 30px;
  color: var(--dulcedo-gold);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
}

.page {
  background: var(--dulcedo-page-bg);
  min-height: calc(100vh - 62px);
  padding: 32px 28px 64px;
  display: flex;
  justify-content: center;
}

.page > * {
  width: 100%;
  max-width: 720px;
}

.app-state {
  min-height: 40vh;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 32px;
  color: var(--dulcedo-muted);
  font-size: 14px;
}

.is-hidden {
  display: none !important;
}

.gate-inner {
  max-width: 360px;
}

.gate-title {
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.5px;
  color: var(--dulcedo-text);
  margin: 12px 0 4px;
}

.gate-text {
  font-size: 14px;
  line-height: 1.5;
  color: var(--dulcedo-muted);
  margin: 4px 0;
}

.dots-loader {
  display: flex;
  justify-content: center;
  gap: 7px;
  margin-top: 20px;
}

.dots-loader span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--dulcedo-gold);
  display: inline-block;
  animation: dots-bounce 1.4s ease-in-out infinite both;
}

.dots-loader span:nth-child(1) {
  animation-delay: -0.32s;
}

.dots-loader span:nth-child(2) {
  animation-delay: -0.16s;
}

@keyframes dots-bounce {
  0%,
  80%,
  100% {
    transform: scale(0.6);
    opacity: 0.5;
  }
  40% {
    transform: scale(1);
    opacity: 1;
  }
}

.action-bar {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  /* Was flex-wrap: wrap — at 720px that left razor-thin margin, so a longer
     currency code (e.g. "$12,000 CAD" vs "$8,000 USD") was enough to tip
     the row over and wrap the buttons onto their own line. Never wrap on
     desktop; the mobile media query below re-enables wrapping/stacking for
     genuinely narrow viewports where it's actually needed. */
  flex-wrap: nowrap;
  gap: 12px;
  margin-bottom: 14px;
}

.doc-ref {
  font-size: 13px;
  color: var(--dulcedo-muted);
  margin-top: 2px;
}

.doc-ref--lg {
  font-size: 20px;
  font-weight: 800;
  color: var(--dulcedo-text);
  letter-spacing: -0.3px;
}

.action-bar__right {
  display: flex;
  align-items: center;
  gap: 10px;
}

.action-bar__actions {
  display: flex;
  gap: 8px;
}

.btn-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 2px;
  border: 0.5px solid var(--dulcedo-muted);
  background: transparent;
  color: var(--dulcedo-text);
  cursor: pointer;
  flex-shrink: 0;
}

.btn-icon:hover {
  border-color: var(--dulcedo-gold);
  color: var(--dulcedo-gold);
}

.status-ribbon {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}

.status-ribbon__label {
  background: var(--dulcedo-gold);
  color: #0a0a0a;
  font-weight: 800;
  font-size: 12px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  padding: 9px 18px;
  border-radius: 2px;
  white-space: nowrap;
}

.status-ribbon__label--accepted {
  background: #2f6f4a;
  color: #ffffff;
}

.status-ribbon__label--review {
  background: #d9822b;
  color: #ffffff;
}

.btn {
  border-radius: 2px;
  padding: 10px 14px;
  font-weight: 800;
  font-size: 13px;
  letter-spacing: 0.3px;
  cursor: pointer;
  font-family: inherit;
}

.btn-primary {
  background: var(--dulcedo-gold);
  color: #0a0a0a;
  border: none;
}

.btn-secondary {
  background: transparent;
  color: var(--dulcedo-text);
  border: 0.5px solid var(--dulcedo-muted);
}

.btn[disabled] {
  opacity: 0.6;
  cursor: default;
}

.agent-note {
  text-align: center;
  font-size: 13px;
  color: var(--dulcedo-muted);
  background: var(--dulcedo-card-bg);
  border: 0.5px solid var(--dulcedo-gold);
  border-radius: 2px;
  padding: 10px 16px;
  margin-bottom: 14px;
}

.agent-note__cta {
  color: var(--dulcedo-gold-dark);
  font-weight: 800;
}

.doc-card {
  position: relative;
  overflow: hidden;
  background: var(--dulcedo-card-bg);
  border: 0.5px solid var(--dulcedo-border);
  border-radius: 2px;
  padding: 32px;
}

.corner-ribbon {
  position: absolute;
  top: 26px;
  right: -42px;
  width: 160px;
  transform: rotate(45deg);
  color: #ffffff;
  text-align: center;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  padding: 6px 0;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
}

.corner-ribbon--review {
  background: #d9822b;
}

.corner-ribbon--accepted {
  background: #2f6f4a;
}

/* Wraps doc-card + the "message to your agent" box so the comment can sit
   beside the document instead of stacked below it. Only two children in
   practice; .comment-card is-hidden except during Request-changes edit mode. */
.doc-layout {
  display: flex;
  align-items: flex-start;
  gap: 16px;
}

/* Comment box sits after doc-card in the DOM and renders on the right,
   in natural document order — no `order` override needed. */
.comment-card {
  flex: 0 0 390px; /* 260px + 50% */
  background: var(--dulcedo-card-bg);
  border: 0.5px solid var(--dulcedo-border);
  border-radius: 2px;
  padding: 20px 24px;
  margin-top: 0;
}

.doc-layout .doc-card {
  flex: 1;
  min-width: 0;
}

/* [REF] Message box cut off / not centered — widening .doc-layout itself
   (its old approach) doesn't work: per the CSS spec, "auto" margins only
   center a box that's NARROWER than its containing block. Once .doc-layout
   (1126px) is wider than its containing block, #app-main (capped at 720px
   by ".page > *" below), the spec requires the browser to treat auto
   margins as 0 instead of centering — confirmed live via getComputedStyle:
   margin-left resolved to 0px and margin-right to a negative value, i.e.
   pinned left and overflowing only to the right, never centered.
   Fix: widen #app-main itself (the box .page actually centers via
   justify-content) instead of just its child. Since #app-main is no longer
   reliably 720px, its OTHER children (action-bar, banners, agent-note) get
   their own explicit 720px cap + auto-centering right below — that works
   normally since 720px still fits inside the wider #app-main with room to
   spare, so auto margins behave as expected there. */
#app-main:has(#change-comment:not(.is-hidden)) {
  max-width: calc(720px + 16px + 390px);
}

/* Left-aligned, not centered: doc-card itself sits flush against
   #app-main's left edge (it's just the first item in the .doc-layout flex
   row, with comment-card filling the remaining width to its right) — so
   these siblings need to match that same left edge, not center within the
   full widened #app-main, or the action bar drifts out of alignment with
   the document underneath it whenever the comment box is open. */
#app-main > *:not(.doc-layout) {
  width: 100%;
  max-width: 720px;
}

.comment-card textarea {
  width: 100%;
  background: transparent;
  border: 0.5px solid var(--dulcedo-border);
  border-radius: 2px;
  color: var(--dulcedo-text);
  font-size: 13px;
  font-family: inherit;
  padding: 10px;
  resize: vertical;
}

.comment-card textarea:focus,
.comment-card textarea:focus-visible {
  outline: none;
  border-color: var(--dulcedo-gold);
  box-shadow: 0 0 0 1px var(--dulcedo-gold);
}

.comment-card textarea::placeholder {
  color: var(--dulcedo-muted);
  font-style: italic;
}

.comment-help {
  font-size: 11px;
  line-height: 1.5;
  color: var(--dulcedo-muted);
  margin: 6px 0 12px;
}

.comment-char-error {
  font-size: 11px;
  font-weight: 700;
  color: #b3261e;
  margin-top: 6px;
}

.doc-logo {
  /* Logo includes the circle mark stacked above the wordmark, so it needs
     more height than the old 56px text to read at the same visual weight. */
  display: block;
  height: 120px;
  width: auto;
  margin: 0 auto 24px;
}

.doc-cols {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 16px;
  padding-bottom: 16px;
  border-bottom: 1.5px solid var(--dulcedo-gold);
  margin-bottom: 16px;
}

.sec-label {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--dulcedo-muted);
  margin-bottom: 6px;
}

.sec-label--spaced {
  margin-top: 20px;
}

.doc-text {
  font-size: 13px;
  line-height: 1.6;
  color: var(--dulcedo-text);
}

.doc-text-locked {
  font-size: 13px;
  color: var(--dulcedo-muted);
}

.doc-mini-row {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 13px;
  color: var(--dulcedo-text);
  line-height: 1.6;
}

.doc-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 5px 0;
  font-size: 13px;
  color: var(--dulcedo-text);
}

.doc-row--bottom {
  border-bottom: 1.5px solid var(--dulcedo-gold);
  padding-bottom: 12px;
  margin-bottom: 4px;
}

.doc-row-label {
  color: var(--dulcedo-muted);
}

.doc-row-label--required::after {
  content: " *";
  color: #b3261e;
  font-weight: 700;
}

.doc-row-label--with-hint {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.hint-icon {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 0.5px solid var(--dulcedo-muted);
  color: var(--dulcedo-muted);
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  cursor: help;
}

/* [REF] Change tool tip on Special Request (per JJ) — "make it faster":
   custom bubble shown via :hover/:focus with a near-instant transition,
   instead of the native `title` attribute's ~1s browser-controlled delay. */
.hint-icon__bubble {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 220px;
  /* Same card/modal treatment as .modal-box — card bg, hairline border,
     2px radius — instead of an inverted ad-hoc dark tooltip. Font inherits
     the app's own Helvetica Now Display stack from body. */
  background: var(--dulcedo-card-bg);
  color: var(--dulcedo-text);
  border: 0.5px solid var(--dulcedo-border);
  border-radius: 2px;
  padding: 8px 10px;
  font-size: 11px;
  font-weight: 400;
  font-family: inherit;
  line-height: 1.4;
  text-align: left;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  opacity: 0;
  visibility: hidden;
  transition: opacity 80ms ease;
  pointer-events: none;
  z-index: 20;
}

.hint-icon:hover .hint-icon__bubble,
.hint-icon:focus .hint-icon__bubble,
.hint-icon:focus-visible .hint-icon__bubble {
  opacity: 1;
  visibility: visible;
}

.deliv-table {
  width: 100%;
  font-size: 13px;
  color: var(--dulcedo-text);
  border-collapse: collapse;
  /* Fixed layout + an explicit width on the scope column below — otherwise
     an unusually long Description value (auto layout looks at content
     across the whole column) squeezes scope down until even short names
     like "Event Appearances" wrap and crowd right up against Description
     with no gap. */
  table-layout: fixed;
}

.deliv-table--spaced {
  margin-top: 20px;
}

.deliv-table td {
  padding: 6px 12px 6px 0;
  border-bottom: 0.5px solid var(--dulcedo-border);
  /* Top-align so a short scope/qty value doesn't float to the vertical
     center of a row whose Description wraps across several lines. */
  vertical-align: top;
}

.deliv-table th:first-child,
.deliv-table td:first-child {
  width: 150px;
}

.deliv-table td.qty,
.deliv-table th.qty {
  text-align: right;
  width: 90px;
  padding-right: 0;
  color: var(--dulcedo-muted);
}

.deliv-table td.desc,
.deliv-table th.desc {
  color: var(--dulcedo-muted);
  font-size: 12px;
  overflow-wrap: anywhere;
  word-break: break-word;
}

.deliv-table th {
  padding: 0 0 6px;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--dulcedo-muted);
  text-align: left;
  border-bottom: 0.5px solid var(--dulcedo-border);
}

.deliv-amount {
  color: var(--dulcedo-gold);
}

.deliv-total-row td {
  border-bottom: none;
  border-top: 1.5px solid var(--dulcedo-gold);
  padding-top: 10px;
  font-weight: 800;
}

.deliv-total-row .deliv-amount {
  font-size: 15px;
}

.deliv-tax-note-row td {
  border-bottom: none;
  padding-top: 6px;
}

.tax-note {
  font-size: 11px;
  font-style: italic;
  font-weight: 400;
  color: var(--dulcedo-muted);
}

.doc-disclaimer {
  font-size: 11px;
  font-weight: 400;
  line-height: 1.5;
  color: var(--dulcedo-muted);
  border-top: 0.5px solid var(--dulcedo-border);
  margin: 24px 0 0;
  padding-top: 16px;
}

.doc-amount {
  font-size: 30px;
  font-weight: 800;
  color: var(--dulcedo-text);
  letter-spacing: -0.5px;
}

.v-input {
  background: transparent;
  border: none;
  border-bottom: 1px dashed var(--dulcedo-gold);
  border-radius: 5px;
  color: var(--dulcedo-text);
  font-size: 13px;
  font-family: inherit;
  /* Horizontal padding is always on so focus background doesn't shift layout */
  padding: 2px 4px;
  width: 100%;
  outline: none;
  transition: background 0.15s ease, border-bottom-color 0.15s ease;
}

.v-input:focus,
.v-input:focus-visible {
  outline: none;
  /* Soft gold wash — matches Dulcedo accent without a hard black ring */
  background: color-mix(in srgb, var(--dulcedo-gold) 22%, transparent);
  border-bottom-color: var(--dulcedo-gold);
  border-bottom-style: solid;
}

.v-input--select {
  width: auto;
  max-width: 160px;
  background: var(--dulcedo-card-bg);
  cursor: pointer;
}

.v-input--select:focus,
.v-input--select:focus-visible {
  background: color-mix(in srgb, var(--dulcedo-gold) 22%, var(--dulcedo-card-bg));
}

/* Required payment method — solid gold underline + soft tint so it reads as
   required before submit, not the same dashed look as optional fields.
   (Was red — switched to the same gold used elsewhere; only the color
   changed, the solid-underline/tint treatment itself stays.) */
.v-input--required {
  border-bottom-color: var(--dulcedo-gold);
  border-bottom-style: solid;
  background: color-mix(in srgb, var(--dulcedo-gold) 8%, var(--dulcedo-card-bg));
}

.v-input--required:focus,
.v-input--required:focus-visible {
  background: color-mix(in srgb, var(--dulcedo-gold) 14%, var(--dulcedo-card-bg));
  border-bottom-color: var(--dulcedo-gold);
}

.v-input::placeholder {
  color: var(--dulcedo-muted);
  font-style: italic;
  font-size: 10px;
  opacity: 1;
}

/* [REF] Message box cut off — below this width there isn't enough room for
   the document (720px cap) + gap + comment box (390px) side by side without
   overflowing the visible viewport (no scroll affordance shown), so the
   comment box was silently cut off on common laptop/non-maximized window
   widths. Separate, wider breakpoint from the 640px block below — this is
   only about the two-column comment layout, not general mobile spacing. */
@media (max-width: 1200px) {
  .doc-layout {
    flex-direction: column;
  }

  .comment-card {
    order: 0;
    flex: none;
    width: 100%;
    margin-top: 16px;
  }

  #app-main:has(#change-comment:not(.is-hidden)) {
    max-width: 720px;
  }
}

@media (max-width: 640px) {
  /* Not enough room at this width even with the tightened desktop spacing —
     go back to wrapping/stacking here, unlike the 720px desktop layout. */
  .action-bar {
    flex-wrap: wrap;
  }

  .doc-cols {
    grid-template-columns: 1fr;
    gap: 12px;
  }

  .doc-card {
    padding: 20px;
  }

  .page {
    padding: 20px 14px 48px;
  }

  /* Not enough width for a side-by-side layout — back to stacked, comment
     box below the document like before, and drop the extra max-width. */
  .doc-layout {
    flex-direction: column;
  }

  .comment-card {
    order: 0;
    flex: none;
    width: 100%;
    margin-top: 16px;
  }

  /* Undo the desktop-only overflow width — not enough room to sit beside
     doc-card here, so #app-main goes back to its normal 720px cap and the
     comment box stacks below at 100% instead. */
  #app-main:has(#change-comment:not(.is-hidden)) {
    max-width: 720px;
  }
}

.toggle-switch {
  position: relative;
  display: inline-block;
  width: 38px;
  height: 21px;
  flex-shrink: 0;
  cursor: pointer;
}

.toggle-switch__input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.toggle-switch__track {
  position: absolute;
  inset: 0;
  background: var(--dulcedo-border);
  border-radius: 999px;
  transition: background 0.15s ease;
}

.toggle-switch__track::before {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 17px;
  height: 17px;
  background: #ffffff;
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  transition: transform 0.15s ease;
}

.toggle-switch__input:checked + .toggle-switch__track {
  background: var(--dulcedo-gold);
}

.toggle-switch__input:checked + .toggle-switch__track::before {
  transform: translateX(17px);
}

.toggle-switch__input:focus-visible + .toggle-switch__track {
  outline: 2px solid var(--dulcedo-gold-dark);
  outline-offset: 2px;
}

.toggle-switch__input:disabled + .toggle-switch__track {
  opacity: 0.5;
}

.toggle-switch:has(.toggle-switch__input:disabled) {
  cursor: not-allowed;
}

.v-input--platform {
  width: auto;
  max-width: 200px;
}

/* Payment method/platform validation banner — sits between the action bar
   and the document (same slot as .agent-note) so it's visible right where
   the client is already looking after clicking Accept/Submit changes,
   without needing to scroll down to the payment fields themselves. */
.payment-info-banner {
  text-align: center;
  font-size: 13px;
  font-weight: 600;
  color: #b3261e;
  background: var(--dulcedo-card-bg);
  border: 0.5px solid #b3261e;
  border-radius: 2px;
  padding: 10px 16px;
  margin-bottom: 14px;
}

/* Applied to payment-method-select/payment-platform-input specifically —
   whichever one(s) validatePaymentInfo() found missing — same red used by
   .payment-info-banner above. */
.v-input.is-invalid {
  border-bottom-color: #b3261e;
}

/* "Only one change request" confirm dialog — shown on Request-changes click,
   before setEditing(true) actually runs (see main.js). */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 100;
}

.modal-box {
  background: var(--dulcedo-card-bg);
  border: 0.5px solid var(--dulcedo-border);
  border-radius: 2px;
  padding: 24px;
  max-width: 380px;
  width: 100%;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
}

.modal-text {
  color: var(--dulcedo-text);
  font-size: 14px;
  line-height: 1.5;
  margin: 0 0 20px;
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

/* Download-PDF uses window.print() — this trims the page down to just the
   estimate itself: no navbar, no action buttons, no comment box. */
@media print {
  .topbar,
  .action-bar,
  .agent-note,
  .payment-info-banner,
  .modal-overlay,
  #change-comment {
    display: none !important;
  }

  body,
  .page {
    background: #ffffff !important;
    padding: 0 !important;
  }

  .page > * {
    max-width: 100% !important;
  }

  .doc-card {
    border: none !important;
    padding: 0 !important;
  }
}
