/* =============================================================================
   PlotPDFPro Portal — Component layer
   Reusable primitives only. No page-specific rules.
   Every value is a token; no literal colours or lengths (see tokens.css).
   ============================================================================= */

/* ---------------------------------------------------------------- Button (DL §10.1) */
.pp-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: var(--control-height);
  min-width: var(--touch-target-min);
  padding-inline: var(--space-4);
  border: var(--hairline) solid transparent;
  border-radius: var(--radius-md);
  font-size: var(--type-body-size);
  line-height: var(--type-body-line);
  font-weight: var(--weight-strong);
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  transform: translateY(0);
  /* ACP-DESIGN-001C: the press is faster than the release, and both use --ease-precise rather than
     the standard curve. A control that answers a click on the same curve it relaxes on feels soft;
     a control that arrives sharply and relaxes slowly feels made of something. The asymmetry is
     small enough that nobody sees it and large enough that everybody feels it. */
  transition:
    transform var(--motion-base) var(--ease-precise),
    box-shadow var(--motion-base) var(--ease-precise),
    background-color var(--motion-fast) var(--ease-precise),
    border-color var(--motion-fast) var(--ease-precise);
}

/* Hover lifts 2 px and deepens the shadow; click settles 1 px below rest (DL §10.1). */
.pp-button:hover:not(:disabled) {
  transform: translateY(calc(var(--space-1) / -2));
  box-shadow: var(--elevation-2);
}

.pp-button:active:not(:disabled) {
  transform: translateY(calc(var(--space-1) / 4));
  box-shadow: var(--elevation-1);
  /* The press lands immediately. Easing into a click is the single clearest way to make a control
     feel like it is thinking about it. */
  transition-duration: var(--motion-instant);
}

.pp-button:disabled {
  opacity: 0.4;
  cursor: default;
  transform: translateY(0);
  box-shadow: none;
}

.pp-button--primary {
  background-color: var(--accent-default);
  color: var(--text-on-accent);
  box-shadow: var(--elevation-1);
}

.pp-button--primary:hover:not(:disabled) { background-color: var(--accent-hover); }
.pp-button--primary:active:not(:disabled) { background-color: var(--accent-pressed); }

.pp-button--secondary {
  background-color: var(--surface-default);
  border-color: var(--border-strong);
  color: var(--text-primary);
  box-shadow: var(--elevation-1);
}

.pp-button--tertiary {
  background-color: transparent;
  color: var(--text-secondary);
}

.pp-button--tertiary:hover:not(:disabled) {
  background-color: var(--surface-sunken);
  box-shadow: none;
  transform: translateY(0);
}

.pp-button--danger {
  background-color: var(--danger-default);
  color: var(--text-on-accent);
  box-shadow: var(--elevation-1);
}

.pp-button--small { min-height: var(--control-height-sm); padding-inline: var(--space-3); }
.pp-button--large { min-height: var(--control-height-lg); padding-inline: var(--space-5); }
.pp-button--block { width: 100%; }

/* Width must not change while loading; layout shift reads as instability (DL §10.1). */
.pp-button__spinner {
  width: var(--space-3);
  height: var(--space-3);
  border: calc(var(--hairline) * 2) solid currentColor;
  border-top-color: transparent;
  border-radius: var(--radius-full);
  animation: pp-spin 1400ms var(--ease-linear) infinite;
}

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

/* ---------------------------------------------------------------- Card (DL §10.2) */
.pp-card {
  display: block;
  padding: var(--space-4);
  border: var(--hairline) solid var(--border-default);
  border-top-color: var(--elevation-top-border);
  border-radius: var(--radius-lg);
  background-color: var(--surface-default);
  box-shadow: var(--elevation-1);
}

.pp-card--raised { background-color: var(--surface-raised); box-shadow: var(--elevation-2); }
.pp-card--flat { box-shadow: none; }

/* Lift belongs only to cards that are actually clickable. */
.pp-card--interactive {
  cursor: pointer;
  transform: translateY(0);
  transition:
    transform var(--motion-fast) var(--ease-standard),
    box-shadow var(--motion-fast) var(--ease-standard);
}

.pp-card--interactive:hover {
  transform: translateY(calc(var(--space-1) / -2));
  box-shadow: var(--elevation-2);
}

/* ---------------------------------------------------------------- Input (DL §10.3) */
.pp-field { display: flex; flex-direction: column; gap: var(--space-1); }

.pp-field__label {
  font-size: var(--type-body-size);
  line-height: var(--type-body-line);
  font-weight: var(--weight-strong);
  color: var(--text-primary);
}

.pp-input {
  min-height: var(--control-height);
  padding-inline: var(--space-3);
  border: var(--hairline) solid var(--border-strong);
  border-radius: var(--radius-sm);
  background-color: var(--surface-default);
  color: var(--text-primary);
  transition: border-color var(--motion-fast) var(--ease-standard);
}

.pp-input::placeholder { color: var(--text-placeholder); }
.pp-input:hover:not(:disabled) { border-color: var(--text-placeholder); }
.pp-input:disabled { opacity: 0.4; cursor: default; }
.pp-input--invalid { border-color: var(--danger-default); }

/* Error is never colour alone: an icon and text always accompany it (DL §3.8). */
.pp-field__message {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
  color: var(--text-tertiary);
}

.pp-field__message--error { color: var(--danger-default); }

/* ---------------------------------------------------------------- Modal (DL §10) */
.pp-modal__scrim {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background-color: var(--surface-sunken);
  animation: pp-fade-in var(--motion-base) var(--ease-enter);
}

.pp-modal {
  width: 100%;
  max-width: var(--container-text);
  max-height: calc(100vh - var(--space-8));
  overflow-y: auto;
  padding: var(--space-5);
  border: var(--hairline) solid var(--border-default);
  border-top-color: var(--elevation-top-border);
  border-radius: var(--radius-xl);
  background-color: var(--surface-raised);
  box-shadow: var(--elevation-3);
  animation: pp-rise-in var(--motion-slow) var(--ease-enter);
}

/* The title takes the room it needs and the close control keeps its corner; align-items is start so a
   two-line title does not drag the X down with it. */
.pp-modal__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.pp-modal__close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--control-height-sm);
  block-size: var(--control-height-sm);
  margin: calc(var(--space-1) * -1) calc(var(--space-2) * -1) 0 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
}

.pp-modal__close:hover { color: var(--text-primary); background-color: var(--surface-sunken); }

.pp-modal__body { margin-bottom: var(--space-5); }
.pp-modal__footer { display: flex; justify-content: flex-end; gap: var(--space-2); }

/* On a phone the dialog legitimately takes most of the viewport — it is the task. The footer stops
   being a right-aligned pair, because two buttons side by side at 375px leave neither with a
   comfortable target, and the scrim's padding shrinks so the dialog is not squeezed into a column. */
@media (max-width: 767px) {
  .pp-modal__scrim { padding: var(--space-3); align-items: flex-start; }
  .pp-modal { max-height: calc(100dvh - var(--space-6)); padding: var(--space-4); }
  .pp-modal__footer { flex-direction: column-reverse; }
  .pp-modal__footer .pp-button { inline-size: 100%; }

  /* A form this tall scrolls inside the dialog, and the close control must not scroll away with the
     title: the way out of a dialog has to stay on screen the whole time it is open. The negative
     offsets pull the bar over the dialog's own padding so it meets the rounded corners cleanly. */
  .pp-modal__header {
    position: sticky;
    inset-block-start: calc(var(--space-4) * -1);
    z-index: 1;
    margin-block-start: calc(var(--space-4) * -1);
    margin-inline: calc(var(--space-4) * -1);
    padding: var(--space-4) var(--space-4) var(--space-2);
    background-color: var(--surface-raised);
  }
}

/* Entering elements move and fade together; either alone reads wrong (DL §9.3). */
@keyframes pp-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes pp-rise-in {
  from { opacity: 0; transform: translateY(var(--space-2)); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---------------------------------------------------------------- Banner (DL §10.5) */
.pp-banner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-3);
  border: var(--hairline) solid var(--border-default);
  border-radius: var(--radius-md);
  background-color: var(--surface-default);
  color: var(--text-primary);
}

.pp-banner__icon { flex: none; margin-top: calc(var(--space-1) / 2); }
.pp-banner__content { flex: 1 1 auto; }

.pp-banner--info    { border-color: var(--info-default); }
.pp-banner--success { border-color: var(--success-default); background-color: var(--success-subtle); }
.pp-banner--warning { border-color: var(--warning-default); }
.pp-banner--danger  { border-color: var(--danger-default); }

/* ---------------------------------------------------------------- Toast (DL §10.5) */
.pp-toast-region {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  width: min(var(--container-reading), calc(100vw - var(--space-7)));
  pointer-events: none;
}

.pp-toast {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-3);
  border: var(--hairline) solid var(--border-default);
  border-top-color: var(--elevation-top-border);
  border-radius: var(--radius-md);
  background-color: var(--surface-raised);
  box-shadow: var(--elevation-2);
  pointer-events: auto;
  animation: pp-rise-in var(--motion-base) var(--ease-enter);
}

.pp-toast--success { border-color: var(--success-default); }
.pp-toast--danger  { border-color: var(--danger-default); }

/* ---------------------------------------------------------------- Progress Ring (DL §10.4)
   The signature component. Completion sequence:
     red → green (400 ms ceremony) → checkmark draws (350 ms) → two-leaf at +250 ms. */
.pp-ring {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.pp-ring__svg { transform: rotate(-90deg); }

.pp-ring__track { stroke: var(--surface-sunken); fill: none; }

.pp-ring__fill {
  fill: none;
  stroke: var(--accent-default);
  stroke-linecap: round;
  transition:
    stroke-dashoffset var(--motion-base) var(--ease-standard),
    stroke var(--motion-ceremony) var(--ease-standard);
}

.pp-ring--complete .pp-ring__fill { stroke: var(--success-default); }

/* Indeterminate: one full turn every 1.4 s. Never a fake percentage (DL §10.4). */
.pp-ring--indeterminate .pp-ring__svg {
  animation: pp-spin 1400ms var(--ease-linear) infinite;
}

.pp-ring--indeterminate .pp-ring__fill { transition: none; }

.pp-ring__label {
  position: absolute;
  font-size: var(--type-title2-size);
  line-height: var(--type-title2-line);
  font-weight: var(--weight-strong);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

.pp-ring__status {
  position: absolute;
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
  color: var(--text-secondary);
  text-align: center;
  max-width: 60%;
}

/* Checkmark is drawn, not popped. */
.pp-ring__check {
  position: absolute;
  fill: none;
  stroke: var(--success-default);
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
}

.pp-ring--complete .pp-ring__check {
  animation: pp-draw-check var(--motion-slow) var(--ease-standard) forwards;
}

@keyframes pp-draw-check {
  to { stroke-dashoffset: 0; }
}

/* Two-leaf brand signature: appears 250 ms after the checkmark begins, at the
   upper-right corner of the mark. Elegant and quiet — no particles, no confetti,
   no fireworks, no exaggerated celebration (DL §11.3, task requirement 10). */
.pp-ring__leaf {
  position: absolute;
  top: 12%;
  right: 12%;
  opacity: 0;
  fill: none;
  stroke: var(--success-default);
  stroke-linecap: round;
  stroke-linejoin: round;
}

.pp-ring--complete .pp-ring__leaf {
  animation: pp-leaf-in var(--motion-base) var(--ease-enter) var(--motion-leaf-delay) forwards;
}

/* Rises and fades in only. No scale overshoot, no rotation, no bounce. */
@keyframes pp-leaf-in {
  from { opacity: 0; transform: translateY(var(--space-1)); }
  to   { opacity: 1; transform: translateY(0); }
}

.pp-ring--small .pp-ring__label {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
}

/* ---------------------------------------------------------------- Icon (DL §15) */
.pp-icon {
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---------------------------------------------------------------- App shell */
.pp-app {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.pp-header {
  position: sticky;
  top: 0;
  z-index: 40;
  border-bottom: var(--hairline) solid var(--border-default);
  background-color: var(--surface-default);
}

.pp-header__inner {
  position: relative;
  display: grid;
  grid-template-columns: minmax(max-content, 1fr) minmax(0, max-content) minmax(max-content, 1fr);
  align-items: center;
  gap: var(--space-4);
  min-height: var(--space-7);
}

.pp-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--type-title3-size);
  line-height: var(--type-title3-line);
  font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-title3);
  color: var(--text-primary);
  text-decoration: none;
  justify-self: start;
}

.pp-brand__logo {
  inline-size: clamp(2.75rem, 5vw, 3.5rem);
  block-size: auto;
  flex: none;
  color: var(--accent-default);
}

.pp-brand__wordmark { white-space: nowrap; }

.pp-brand__accent { color: var(--accent-default); }

/* Equal flexible outer tracks keep the promotion on the hero/container centre axis while giving the
   brand and navigation real, non-overlapping grid cells. Authenticated navigation uses an intentional
   short label; the theme control therefore remains visible and clickable instead of sitting under an
   absolutely positioned sentence. */
.pp-header__promo {
  grid-column: 2;
  min-inline-size: 0;
  max-inline-size: 100%;
  margin: 0;
  text-align: center;
  font-size: 0.8125rem;
  line-height: 1.35;
  font-weight: 400;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}

.pp-header__promo-compact { display: none; }
.pp-header__inner:has(.pp-account) .pp-header__promo-full { display: none; }
.pp-header__inner:has(.pp-account) .pp-header__promo-compact { display: inline; }

/* Below this width the header cannot hold brand + slogan + controls on one line, so the slogan
   yields rather than wrapping. The message still reaches the reader in the hero copy. */
@media (max-width: 1100px) {
  .pp-header__promo { display: none; }
}

.pp-nav {
  grid-column: 3;
  justify-self: end;
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: var(--space-1);
  min-inline-size: max-content;
}

.pp-nav__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--control-height-sm);
  padding-inline: var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  text-decoration: none;
  transition:
    background-color var(--motion-fast) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard);
}

.pp-nav__link:hover { background-color: var(--surface-sunken); color: var(--text-primary); }

.pp-nav__link--active {
  color: var(--text-primary);
  font-weight: var(--weight-strong);
}

/* Positioned so the corporate dock inside it can be anchored to its lower edge. main already fills the
   space between header and footer, and on the home page its lower edge IS the bottom of the animated
   drawing, which is exactly where the card belongs. */
.pp-main { flex: 1 1 auto; position: relative; }

/* The dock contributes no layout height: it is taken out of flow and pinned to the bottom of main, so
   the footer sits where it would have sat with no card at all. Only the card itself is interactive —
   the dock spans the full width and would otherwise swallow clicks on the page underneath it. */
.pp-corp-dock {
  position: absolute;
  inset-inline: 0;
  inset-block-end: var(--space-4);
  z-index: 2;                      /* over the drawing, under the header, modal and toast */
  pointer-events: none;
}

.pp-corp-dock__inner {
  display: flex;
  justify-content: flex-end;       /* right edge lands on the container rhythm the footer uses */
}

.pp-corp-dock .pp-corp-cta { pointer-events: auto; }

.pp-footer {
  border-top: var(--hairline) solid var(--border-default);
  padding-block: var(--space-4);
  color: var(--text-tertiary);
}

/* ---------------------------------------------------------------- Theme toggle */
.pp-theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--control-height-sm);
  height: var(--control-height-sm);
  border: var(--hairline) solid var(--border-default);
  border-radius: var(--radius-sm);
  background-color: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition:
    background-color var(--motion-fast) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard);
}

.pp-theme-toggle:hover { background-color: var(--surface-sunken); color: var(--text-primary); }

.pp-language {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 74px;
  height: var(--control-height-sm);
  padding-inline: var(--space-2);
  border: var(--hairline) solid var(--border-default);
  border-radius: var(--radius-sm);
  color: var(--text-tertiary);
  font-size: var(--type-caption-size);
  font-weight: var(--weight-strong);
}

.pp-language__choice {
  min-width: 24px;
  padding: var(--space-1);
  color: var(--text-tertiary);
  text-align: center;
  text-decoration: none;
  border-radius: calc(var(--radius-sm) - 2px);
}

.pp-language__choice:hover,
.pp-language__choice:focus-visible { color: var(--text-primary); background: var(--surface-sunken); }
.pp-language__choice.is-selected { color: var(--text-primary); text-decoration: underline; text-underline-offset: 3px; }

/* ---------------------------------------------------------------- Global loading overlay
   Uses the Portal Progress Ring; no third-party spinner library is introduced. */
.pp-overlay {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--surface-canvas);
  animation: pp-fade-in var(--motion-fast) var(--ease-enter);
}

.pp-overlay__panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-5);
  border-radius: var(--radius-xl);
  background-color: var(--surface-raised);
  box-shadow: var(--elevation-2);
  color: var(--text-secondary);
}

/* ---------------------------------------------------------------- Account area */
.pp-account {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.pp-account__initials {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--control-height-sm);
  height: var(--control-height-sm);
  border-radius: var(--radius-full);
  background-color: var(--accent-subtle);
  color: var(--accent-default);
  font-size: var(--type-caption-size);
  font-weight: var(--weight-strong);
}

.pp-account__name { color: var(--text-primary); }

/* ---------------------------------------------------------------- Links */
.pp-link {
  color: var(--text-secondary);
  text-decoration: underline;
  text-underline-offset: var(--space-1);
  transition: color var(--motion-fast) var(--ease-standard);
}

.pp-link:hover { color: var(--accent-default); }

/* ---------------------------------------------------------------- Footer navigation */
.pp-footer__nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.pp-footer__link {
  color: var(--text-tertiary);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
  text-decoration: none;
  transition: color var(--motion-fast) var(--ease-standard);
  /* The responsive audit measured these at 20px tall, under the 24px minimum target size. The
     padding grows the target without changing the type size or the spacing between rows. */
  display: inline-flex;
  align-items: center;
  min-block-size: var(--touch-target-compact);
}

.pp-footer__link:hover { color: var(--text-primary); }

.pp-footer__consent {
  padding: 0;
  border: 0;
  background: transparent;
  font: inherit;
  cursor: pointer;
}

/* ---------------------------------------------------------------- Landing
   Google-homepage simplicity: everything centred, generous breathing space, one pair of actions. */
.pp-landing {
  display: flex;
  /* ACP-DESIGN-001B: this was `row`, which laid the hero and the "AutoCAD ile doğrudan çalışın"
     section out as two narrow columns side by side — both sections declare width:100% and a top
     margin, so stacking was always the intent. The bug only became obvious once a third section
     was added and the page split into three columns. */
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: calc(100vh - var(--space-9));
  padding-block: var(--space-8);
  padding-inline: var(--page-margin-desktop);
}

.pp-landing__center {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  width: 100%;
  max-width: var(--container-text);
  gap: var(--space-4);
}

.pp-landing__logo {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
}

.pp-landing__logo-mark { color: var(--accent-default); }

.pp-landing__tagline {
  color: var(--text-secondary);
  max-width: var(--container-reading);
}

/* ---------------------------------------------------------------- Hero (ACP-DESIGN-001B)
   The drawing is painted behind the words and must never compete with them. Two things keep it
   honest: it is absolutely positioned underneath, and the text sits on its own stacking level with
   nothing between them. If the SVG fails to render, the hero is unchanged. */
/* The drawing belongs to the hero, not to the page. Scoping it here is what keeps its aspect ratio
   honest: `slice` crops to fill, so if this box were the height of the whole page the plan would be
   blown up several times over and cropped to a corner. */
.pp-landing__hero {
  position: relative;
  isolation: isolate;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: var(--signature-aspect);
  min-height: var(--container-hero-min);
}

.pp-landing__signature {
  /* Fades out towards the edges so the drawing reads as a sheet lying under the page rather than as
     a rectangle pasted onto it. Mask, not opacity: the middle stays at full strength. */
  -webkit-mask-image: var(--signature-mask);
  mask-image: var(--signature-mask);
}

/* ACP-DESIGN-001C: the hero's rhythm is set by what each gap has to separate rather than by one
   uniform value. The eyebrow belongs to the headline, so it sits close; the subtitle is a separate
   thought and gets more room; the actions are a decision and get the most. A single gap for all
   three made the hero read as a stack of four unrelated lines. */
.pp-landing__center--hero {
  position: relative;
  z-index: var(--z-raised);
  gap: 0;
  padding-block: var(--space-7);
}

.pp-landing__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-3);
  color: var(--text-secondary);
}

.pp-landing__eyebrow .pp-landing__logo-mark {
  display: inline-flex;
  color: var(--accent-default);
}

/* The one sentence the whole page exists to say. */
.pp-landing__headline {
  margin: 0;
  /* Narrower than the container: the headline breaks across two lines on a wide screen instead of
     running out to a single long one, which is what gives the hero a centre of gravity. */
  max-width: 18ch;
  color: var(--text-primary);
  text-wrap: balance;
}

.pp-landing__center--hero .pp-landing__tagline {
  margin-block-start: var(--space-4);
  /* Held tighter than the general reading measure. Two comfortable lines under a headline reads as
     composed; four reads as a paragraph that wandered into a hero. */
  max-width: 46ch;
}

.pp-landing__actions--hero { margin-block-start: var(--space-6); }

/* The secondary action goes downward on this same page, so its chevron does too. The movement
   answers "where does this take me" before the click rather than after it. */
.pp-button--descend .pp-button__chevron {
  display: inline-flex;
  transform: translateY(0);
  transition: transform var(--motion-base) var(--ease-precise);
}

.pp-button--descend:hover .pp-button__chevron,
.pp-button--descend:focus-visible .pp-button__chevron {
  transform: translateY(var(--space-1));
}

/* ---------------------------------------------------------------- How it works (ACP-DESIGN-001B) */
.pp-steps {
  width: 100%;
  max-width: var(--container-app);
  margin-inline: auto;
  padding-block: var(--space-7);
  /* The anchor target must not land under the sticky header. */
  scroll-margin-top: var(--space-7);
  /* ACP-DESIGN-001C: skip layout and paint for this section until it is near the viewport. The
     contain-intrinsic-size keeps the scrollbar honest in the meantime — without it the page height
     jumps as the section is realised, which is a layout shift traded for a paint saving. */
  content-visibility: auto;
  contain-intrinsic-size: auto var(--container-section-estimate);
}

.pp-steps__title { margin: 0 0 var(--space-2); }
.pp-steps__lead { color: var(--text-secondary); margin: 0 0 var(--space-5); }

.pp-steps__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}

.pp-steps__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-top: var(--space-3);
  /* ACP-DESIGN-001C: a hairline rather than a 2px rule. Four heavy rules across the page read as a
     table; a hairline reads as the setting-out line a drawing is measured from. The step number now
     carries the weight instead, which is where the eye should land anyway. */
  border-top: var(--hairline) solid var(--border-default);
}

.pp-steps__item h3 { margin: 0; }
.pp-steps__item p { margin: 0; color: var(--text-secondary); }

/* Tabular figures so 01/02/03/04 occupy identical width and the four columns align exactly — the
   kind of thing nobody notices until it is wrong. */
.pp-steps__index {
  color: var(--accent-default);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--tracking-caption-strong);
}

@media (min-width: 768px) {
  .pp-steps__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .pp-steps__list { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ---------------------------------------------------------------- Positioning (ACP-MARKETING-001)
   Two sections built from the same layout language as the steps: a construction line to open, a
   heading, a bounded lead, then a grid. Nothing new was invented for them — a third layout pattern
   on the same page would read as a third designer. */
.pp-why,
.pp-audience {
  width: 100%;
  max-width: var(--container-app);
  margin-inline: auto;
  padding-block: var(--space-7);
  content-visibility: auto;
  contain-intrinsic-size: auto var(--container-section-estimate);
}

.pp-why__lead {
  color: var(--text-secondary);
  margin: 0 0 var(--space-3);
}

.pp-why__list {
  margin: var(--space-5) 0 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}

/* A definition list, because that is what this is: a claim and the mechanism behind it. */
.pp-why__item {
  padding-top: var(--space-3);
  border-top: var(--hairline) solid var(--border-default);
}

.pp-why__item dt { margin: 0 0 var(--space-1); color: var(--text-primary); }
.pp-why__item dd { margin: 0; color: var(--text-secondary); }

.pp-audience__list {
  list-style: none;
  margin: var(--space-5) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}

.pp-audience__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding-top: var(--space-2);
  border-top: var(--hairline) solid var(--border-subtle);
}

.pp-audience__item .pp-type-caption { color: var(--text-secondary); }

/* The formats a product converts — the single most important line in that card, and the one a
   visitor scans for. Tabular figures are irrelevant here; the accent is what carries it. */
.pp-desktop__formats {
  color: var(--accent-default);
  margin: var(--space-1) 0 var(--space-2);
}

@media (min-width: 768px) {
  .pp-why__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pp-audience__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .pp-why__list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .pp-audience__list { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Reserved for ACP-PORTAL-003 (upload, drag and drop, progress, download). Holding the space now
   means the layout will not shift when that feature lands. */
.pp-landing__stage {
  width: 100%;
  min-height: var(--space-9);
  margin-block: var(--space-3);
}

.pp-landing__actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.pp-landing__secondary { margin-top: var(--space-2); }

.pp-landing__notice {
  width: 100%;
  max-width: var(--container-reading);
  margin-top: var(--space-3);
}

@media (max-width: 767px) {
  .pp-landing { padding-inline: var(--page-margin-mobile); }
  .pp-landing__actions { flex-direction: column; width: 100%; }
  .pp-account__name { display: none; }
}

/* ---------------------------------------------------------------- Upload surface
   Seven visual states. No transport, no conversion — presentation only. */
.pp-upload {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: var(--upload-min-height);
  padding: var(--space-5);
  border: var(--border-dashed-width) dashed var(--border-strong);
  border-radius: var(--radius-2xl);
  background-color: var(--surface-default);
  transition:
    border-color var(--motion-fast) var(--ease-standard),
    background-color var(--motion-fast) var(--ease-standard),
    box-shadow var(--motion-fast) var(--ease-standard);
}

/* A transparent native input covers the zone, so the browser provides both the picker and the
   drop target without any custom file handling. */
.pp-upload__input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

.pp-upload__body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  text-align: center;
  pointer-events: none;
}

.pp-upload__icon { color: var(--text-placeholder); }
.pp-upload__headline { color: var(--text-primary); }
.pp-upload__hint { color: var(--text-tertiary); }

.pp-upload__selected {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  margin-top: var(--space-2);
  color: var(--text-secondary);
}

.pp-upload__size { color: var(--text-tertiary); }

.pp-upload--idle {
  border-color: var(--border-strong);
}

.pp-upload--hover {
  border-color: var(--text-placeholder);
  box-shadow: var(--elevation-1);
}

.pp-upload--dragging {
  border-color: var(--accent-default);
  background-color: var(--accent-subtle);
  box-shadow: var(--elevation-2);
}

.pp-upload--dragging .pp-upload__icon,
.pp-upload--dragging .pp-upload__headline { color: var(--accent-default); }

.pp-upload--busy {
  border-style: solid;
  border-color: var(--border-default);
}

.pp-upload--complete {
  border-style: solid;
  border-color: var(--success-default);
  background-color: var(--success-subtle);
}

.pp-upload--failed {
  border-style: solid;
  border-color: var(--danger-default);
}

/* ---------------------------------------------------------------- Conversion progress */
.pp-progress {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  flex-wrap: wrap;
  justify-content: center;
}

.pp-progress__detail {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  text-align: left;
  min-width: var(--progress-detail-width);
}

.pp-progress__step { color: var(--text-primary); }
.pp-progress__meta { color: var(--text-secondary); }

/* ---------------------------------------------------------------- Reserved desktop region
   Layout only. No installer, no video, no fabricated download link. */
.pp-desktop {
  width: 100%;
  max-width: var(--container-app);
  margin-inline: auto;
  margin-top: var(--space-9);
  padding-top: var(--space-7);
  border-top: var(--hairline) solid var(--border-subtle);
  text-align: center;
}

.pp-desktop__title { color: var(--text-primary); }

.pp-desktop__lead {
  margin-top: var(--space-2);
  margin-inline: auto;
  max-width: var(--container-reading);
  color: var(--text-secondary);
}

.pp-desktop__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--gutter);
  margin-top: var(--space-6);
  text-align: left;
}

.pp-desktop__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* Holds the space a later task will fill, so the layout does not shift when it lands. */
.pp-desktop__slot {
  display: block;
  margin-top: var(--space-2);
  min-height: var(--space-6);
  border: var(--hairline) dashed var(--border-subtle);
  border-radius: var(--radius-lg);
}

.pp-desktop__slot--media { min-height: var(--space-9); }

@media (max-width: 1023px) {
  .pp-desktop__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 767px) {
  .pp-desktop__grid { grid-template-columns: minmax(0, 1fr); }
  .pp-progress { gap: var(--space-3); }
  .pp-progress__detail { text-align: center; min-width: 0; }
}

/* Ultra-wide: the reading experience must not stretch across the whole display. */
@media (min-width: 1920px) {
  .pp-landing__center { max-width: var(--container-text); }
  .pp-desktop { max-width: var(--container-ultrawide); }
}

/* ---------------------------------------------------------------- Advanced settings
   Collapsed by default, inline, never a modal. Height animates with the standard easing. */
.pp-advanced {
  width: 100%;
  margin-top: var(--space-3);
  text-align: left;
}

.pp-advanced__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: var(--control-height-sm);
  padding-inline: var(--space-2);
  border: none;
  border-radius: var(--radius-sm);
  background-color: transparent;
  color: var(--text-secondary);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
  font-weight: var(--weight-strong);
  cursor: pointer;
  transition: color var(--motion-fast) var(--ease-standard);
}

.pp-advanced__toggle:hover { color: var(--text-primary); }

.pp-advanced__chevron {
  display: inline-flex;
  transition: transform var(--motion-fast) var(--ease-standard);
}

.pp-advanced__chevron--open { transform: rotate(180deg); }

.pp-advanced__panel {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
  transition: grid-template-rows var(--motion-base) var(--ease-standard);
}

.pp-advanced__panel > * { min-height: 0; }

.pp-advanced__panel--open {
  grid-template-rows: 1fr;
}

.pp-choice {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  margin-top: var(--space-3);
  padding: 0;
  border: none;
}

.pp-choice__option {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  min-height: var(--touch-target-min);
  padding: var(--space-2);
  border: var(--hairline) solid var(--border-default);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color var(--motion-fast) var(--ease-standard);
}

.pp-choice__option:hover { border-color: var(--border-strong); }

.pp-choice__option:has(input:checked) {
  border-color: var(--accent-default);
  background-color: var(--accent-subtle);
}

.pp-choice__label {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

@media (min-width: 768px) {
  .pp-choice { flex-direction: row; flex-wrap: wrap; }
  .pp-choice__option { flex: 1 1 var(--container-choice-basis); }
}

/* ---------------------------------------------------------------- conversion history (ACP-PORTAL-005)

   A removed artifact is deliberately NOT given failure styling: the conversion succeeded and was paid
   for, and colouring it red would tell the customer something untrue. Only a genuinely failed
   conversion carries the danger accent. */

.pp-history { padding-block: var(--space-6); display: flex; flex-direction: column; gap: var(--space-5); }
.pp-history__header { display: flex; flex-direction: column; gap: var(--space-2); }
.pp-history__lede { color: var(--text-secondary); max-width: 60ch; }

.pp-history__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.pp-history__card { padding: var(--space-4); }
.pp-history__card--failed { border-inline-start: 3px solid var(--danger-default); }

.pp-history__row { display: flex; flex-direction: column; gap: var(--space-3); }
.pp-history__main { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
/* Long drawing names wrap rather than stretching the card off screen. */
.pp-history__name { overflow-wrap: anywhere; }
.pp-history__meta { color: var(--text-secondary); }

.pp-history__status { display: flex; flex-direction: column; gap: var(--space-1); }
.pp-history__state { font-weight: 600; }
.pp-history__state--ok { color: var(--success-default); }
.pp-history__state--failed { color: var(--danger-default); }
.pp-history__state--cancelled { color: var(--text-secondary); }
.pp-history__state--active { color: var(--text-secondary); }
.pp-history__retention,
.pp-history__reason,
.pp-history__notice { color: var(--text-secondary); }

.pp-history__action { display: flex; align-items: flex-start; }
.pp-history__empty { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-3); align-items: flex-start; }
.pp-history__more { display: flex; justify-content: center; }

@media (min-width: 768px) {
  .pp-history__row { flex-direction: row; align-items: center; gap: var(--space-4); }
  .pp-history__main { flex: 1 1 auto; }
  .pp-history__status { flex: 0 1 22rem; }
  .pp-history__action { flex: 0 0 auto; }
}

/* ---------------------------------------------------------------- account page (ACP-ACCOUNT-001)

   One question, answered by one large number. The value is text at a display size rather than a gauge
   or a coloured ring, so it is readable by a screen reader, at any zoom, and without distinguishing
   colour. Nothing here is styled as currency: these are conversion credits. */

.pp-account-page { padding-block: var(--space-6); display: flex; flex-direction: column; gap: var(--space-5); }
.pp-account-page__header { display: flex; flex-direction: column; gap: var(--space-2); }
.pp-account-page__lede { color: var(--text-secondary); max-width: 60ch; }
.pp-account-page__detail { display: flex; flex-direction: column; gap: var(--space-2); }
.pp-account-page__note { color: var(--text-secondary); max-width: 60ch; }

.pp-credit-card { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-2); }
.pp-credit-card__label { color: var(--text-secondary); }
.pp-credit-card__value {
  font-size: var(--type-hero-size);
  line-height: var(--type-hero-line);
  font-weight: var(--weight-strong);
  font-variant-numeric: tabular-nums;
}
.pp-credit-card__help { color: var(--text-secondary); max-width: 60ch; }

.pp-account-facts { margin: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.pp-account-facts__row { display: flex; justify-content: space-between; gap: var(--space-4); max-width: 32rem; }
.pp-account-facts__row dd { margin: 0; font-variant-numeric: tabular-nums; }
.pp-account-facts__list { margin: 0; padding-inline-start: var(--space-4); display: flex; flex-direction: column; gap: var(--space-1); }

/* Stacks on mobile, sits side by side once there is room. */
.pp-account-page__links { display: flex; flex-direction: column; gap: var(--space-3); }

@media (min-width: 768px) {
  .pp-account-page__links { flex-direction: row; }
  .pp-credit-card { max-width: 32rem; }
}

/* ---------------------------------------------------------------- credit packages (ACP-BILLING-002A)

   Cards, not a pricing table: there are no prices to compare yet, and a table with four empty price
   cells would read as a fault rather than as "not announced". */

.pp-packages { padding-block: var(--space-6); display: flex; flex-direction: column; gap: var(--space-5); }
.pp-packages__header { display: flex; flex-direction: column; gap: var(--space-2); }
.pp-packages__lede { color: var(--text-secondary); max-width: 60ch; }

.pp-packages__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.pp-package { padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); height: 100%; }
.pp-package__credits { margin: 0; }
.pp-package__count { font-size: var(--type-title1-size); font-weight: var(--weight-strong); font-variant-numeric: tabular-nums; }
.pp-package__price { color: var(--text-secondary); }
/* Pushes the action to the card's foot so four cards of different heights still line up. */
.pp-package__action { margin-block-start: auto; }

.pp-packages__empty { padding: var(--space-5); }
.pp-packages__links { display: flex; flex-direction: column; gap: var(--space-3); }

@media (min-width: 600px) {
  .pp-packages__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pp-packages__links { flex-direction: row; }
}

@media (min-width: 1024px) {
  .pp-packages__list { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ---------------------------------------------------------------- content pages (ACP-PORTAL-006)

   Shared by About, FAQ, Support, Contact, Privacy and Terms. These are prose pages, so the type scale
   and the container's reading measure do the work; only lists, fact rows and action groups need
   anything of their own. */

/* Actions wrap on narrow screens instead of pushing the page sideways. */
.pp-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-block-start: var(--space-4); }

.pp-list {
  margin: 0;
  padding-inline-start: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.pp-list li { max-width: 68ch; }

/* Term/definition rows: stacked on mobile so a long value never squeezes its label to one character. */
.pp-facts { margin: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.pp-facts__row { display: flex; flex-direction: column; gap: var(--space-1); }
.pp-facts__row dt { color: var(--text-secondary); }
.pp-facts__row dd { margin: 0; overflow-wrap: anywhere; }

/* AutoCAD launch media. The same compact card is used in the homepage dialog and the long-form
   product page, so the real demonstration keeps one visual treatment at every entry point. */
.pp-autocad-version-highlight {
  max-inline-size: 48rem;
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border: var(--hairline) solid color-mix(in srgb, var(--accent-default) 58%, var(--border-default));
  border-inline-start: 4px solid var(--accent-default);
  border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--accent-default) 10%, var(--surface-raised));
  color: var(--text-primary);
  font-size: clamp(1rem, 1.8vw, 1.25rem);
  line-height: 1.45;
}

.pp-autocad-demo {
  display: grid;
  gap: var(--space-4);
  margin-block: var(--space-4);
  padding: var(--space-4);
  border: var(--hairline) solid var(--border-default);
  border-radius: var(--radius-xl);
  background: var(--surface-sunken);
  box-shadow: var(--elevation-1);
}

.pp-autocad-demo__copy > :first-child { margin-block-start: 0; }
.pp-autocad-demo__copy > :last-child { margin-block-end: 0; }
.pp-autocad-demo__eyebrow {
  margin: 0 0 var(--space-2);
  color: var(--accent-default);
  font-size: var(--type-caption-size);
  font-weight: var(--weight-strong);
  letter-spacing: .08em;
  text-transform: uppercase;
}

.pp-autocad-demo__frame {
  overflow: hidden;
  border: var(--hairline) solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface-canvas);
  aspect-ratio: 16 / 9;
}

.pp-autocad-demo__video {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
}

.pp-product-info__grid {
  display: grid;
  gap: var(--space-4);
}

.pp-product-info__card {
  padding: var(--space-4);
  border: var(--hairline) solid var(--border-default);
  border-radius: var(--radius-xl);
  background: var(--surface-raised);
}

.pp-product-info__card > :first-child { margin-block-start: 0; }
.pp-product-info__card > :last-child { margin-block-end: 0; }
.pp-product-info__faq { display: grid; gap: var(--space-4); }

@media (min-width: 800px) {
  .pp-autocad-demo { grid-template-columns: minmax(14rem, .72fr) minmax(0, 1.5fr); align-items: center; }
  .pp-product-info__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* An unpublished value. Muted and clearly not a real value, never an empty cell. */
.pp-pending { display: inline-flex; align-items: baseline; gap: var(--space-1); color: var(--text-secondary); }
.pp-pending__mark { opacity: 0.6; }
.pp-pending__text { font-style: italic; }

/* The error reference must be selectable and readable; it is what a customer reads out to support. */
.pp-error__reference { margin-block-start: var(--space-3); }
.pp-error__code { font-family: var(--font-mono); overflow-wrap: anywhere; user-select: all; }

@media (min-width: 600px) {
  .pp-facts__row { flex-direction: row; gap: var(--space-4); }
  .pp-facts__row dt { flex: 0 0 14rem; }
}

/* ---------------------------------------------------------------- legal documents (ACP-LEGAL-001)

   Long-form prose. The container's reading measure does most of the work; what these need is a clear
   document header, visible section rhythm, and review markers that are noticeable without shouting. */

.pp-legal { max-width: 100%; }
.pp-legal__header { display: flex; flex-direction: column; gap: var(--space-3); }

/* ACP-DESIGN-001A. Every legal document already carries .pp-legal, so the long-form treatment is
   attached here rather than by adding a class to nine pages — which would have meant editing files
   whose wording is fixed. Body copy moves up to the reading size; headings keep the interface scale,
   because a numbered section heading is a signpost rather than prose.

   The lead paragraph is deliberately excluded: it carries .pp-type-body-large at 17px, and pulling
   it down to the 16px reading size would flatten the one size step that marks it as the summary. */
.pp-legal > p.pp-type-body,
.pp-legal dd,
.pp-legal li { font-size: var(--type-reading-size); line-height: var(--type-reading-line); }

.pp-legal > h2 { margin-block-start: var(--space-4); }
.pp-legal > h3 { margin-block-start: var(--space-2); }
.pp-legal > :first-child { margin-block-start: 0; }

@media (max-width: 599px) {
  .pp-legal .pp-prose { hyphens: auto; }
}

/* Document metadata: stacked on mobile, a compact row of pairs once there is width. */
.pp-legal__meta {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-block: var(--space-3);
  border-block: 1px solid var(--border-subtle, var(--border-default));
}
.pp-legal__meta-row { display: flex; gap: var(--space-2); align-items: baseline; }
.pp-legal__meta-row dt { color: var(--text-secondary); min-width: 9rem; }
.pp-legal__meta-row dd { margin: 0; }

/* A clause only counsel may finalise. Marked, indented and muted — visible without alarming. */
.pp-review-note {
  display: flex;
  gap: var(--space-2);
  color: var(--text-secondary);
  padding-inline-start: var(--space-3);
  border-inline-start: 2px solid var(--border-default);
  font-style: italic;
}
.pp-review-note__mark { font-style: normal; opacity: 0.7; }

.pp-legal-value { overflow-wrap: anywhere; }

.pp-legal-index { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.pp-legal-index__item { display: flex; flex-direction: column; gap: var(--space-1); }
.pp-legal-index__status { color: var(--text-secondary); }

.pp-packages__legal { display: flex; flex-direction: column; gap: var(--space-2); }

@media (min-width: 768px) {
  .pp-legal__meta { flex-direction: row; flex-wrap: wrap; gap: var(--space-5); }
  .pp-legal__meta-row dt { min-width: 0; }
  .pp-legal-index__item { flex-direction: row; justify-content: space-between; align-items: baseline; gap: var(--space-4); }
}

/* =============================================================================
   ACP-DESIGN-001A — Premium design system v1, component layer

   Additions only. Every rule below references semantic tokens; no literal colour or
   length appears here, which the Portal test suite enforces.
   ============================================================================= */

/* ---------------------------------------------------------------- badges

   Colour is reinforcement, never the message: each badge carries text, and the
   subtle variants keep enough contrast to be read in a monochrome screenshot. */

.pp-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-full);
  border: var(--border-width-hairline) solid transparent;
  font-size: var(--type-caption-strong-size);
  line-height: var(--type-caption-strong-line);
  font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-caption-strong);
  white-space: nowrap;
}

.pp-badge__icon { flex: 0 0 auto; }
/* A very long status must wrap out rather than stretch the row it sits in. */
.pp-badge__label { overflow-wrap: anywhere; }

.pp-badge--neutral { background-color: var(--surface-sunken); color: var(--text-secondary); border-color: var(--border-default); }
.pp-badge--success { background-color: var(--success-subtle); color: var(--success-default); border-color: var(--success-default); }
.pp-badge--warning { background-color: var(--surface-sunken); color: var(--warning-default); border-color: var(--warning-default); }
.pp-badge--danger  { background-color: var(--surface-sunken); color: var(--danger-default);  border-color: var(--danger-default); }
.pp-badge--pending { background-color: var(--surface-sunken); color: var(--info-default);    border-color: var(--info-default); }
/* Secondary rather than tertiary text: a badge is caption-sized, and tertiary measured 4.18:1 on the
   sunken surface. Draft still reads quieter than the coloured states because it carries no hue. */
.pp-badge--draft   { background-color: var(--surface-sunken); color: var(--text-secondary);  border-color: var(--border-strong); }
.pp-badge--review  { background-color: var(--surface-sunken); color: var(--warning-default); border-color: var(--border-strong); }
/* Same sunken surface as every other tone. On the accent-subtle surface this measured 3.87:1 in dark
   mode, because that token is lighter than sunken there; the accent border carries the distinction. */
.pp-badge--credit  { background-color: var(--surface-sunken); color: var(--accent-default);  border-color: var(--accent-border); }

/* Repeated on every row of a list: keep the text colour, drop the frame. */
.pp-badge--subtle { background-color: transparent; border-color: transparent; }

/* ---------------------------------------------------------------- skeleton

   Slower than the interaction scale on purpose: at UI speed a placeholder reads as
   activity, at this speed it reads as waiting. */

.pp-skeleton {
  display: block;
  background-color: var(--surface-sunken);
  border-radius: var(--skeleton-radius);
  background-image: linear-gradient(
    90deg,
    var(--surface-sunken) 0%,
    var(--surface-raised) 50%,
    var(--surface-sunken) 100%);
  background-size: 200% 100%;
  animation: pp-skeleton-shimmer var(--skeleton-duration) var(--ease-linear) infinite;
}

.pp-skeleton--line  { height: var(--skeleton-line-height); width: 100%; }
.pp-skeleton--text  { height: var(--type-body-line); width: 100%; }
.pp-skeleton--block { height: var(--space-8); width: 100%; border-radius: var(--radius-md); }
.pp-skeleton--circle { height: var(--icon-xl); width: var(--icon-xl); border-radius: var(--radius-full); }

@keyframes pp-skeleton-shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

/* The global reduced-motion rule collapses the animation; pin the gradient so the
   block does not freeze mid-sweep with a bright band across it. */
@media (prefers-reduced-motion: reduce) {
  .pp-skeleton { background-image: none; }
}

/* ---------------------------------------------------------------- empty states */

.pp-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-2);
  padding: var(--space-6) var(--space-4);
}

.pp-empty__icon { color: var(--text-tertiary); line-height: 0; }
.pp-empty__description { color: var(--text-secondary); max-width: var(--container-reading); }
.pp-empty__action { margin-block-start: var(--space-2); }

/* ---------------------------------------------------------------- tables

   The scroll container is the point: a wide table must scroll inside itself rather
   than widening the page. It is focusable so a keyboard user can reach the scroll. */

.pp-table-scroll {
  overflow-x: auto;
  border: var(--border-width-hairline) solid var(--border-default);
  border-radius: var(--radius-md);
  background-color: var(--surface-default);
}

/* The scroll host is focusable so a keyboard can reach a wide table. Its focus ring comes from the
   one global :focus-visible rule in base.css — repeating it here would be a second place to fix. */

.pp-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--type-body-size);
  line-height: var(--type-body-line);
}

.pp-table__caption {
  caption-side: top;
  text-align: start;
  padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
  color: var(--text-secondary);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
}

.pp-table th,
.pp-table td {
  padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
  text-align: start;
  vertical-align: middle;
  border-block-end: var(--border-width-hairline) solid var(--border-subtle);
}

.pp-table__head th {
  color: var(--text-secondary);
  font-size: var(--type-caption-strong-size);
  line-height: var(--type-caption-strong-line);
  font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-caption-strong);
  text-transform: uppercase;
  background-color: var(--surface-sunken);
  position: sticky;
  top: 0;
  z-index: var(--z-raised);
}

.pp-table__body tr:last-child td { border-block-end: none; }
.pp-table__body tr:hover td { background-color: var(--surface-sunken); }

.pp-table__foot td {
  background-color: var(--surface-sunken);
  font-weight: var(--weight-strong);
  border-block-end: none;
}

.pp-table--compact th,
.pp-table--compact td { padding-block: var(--space-2); }

/* Figures must line up column-wise, so numeric cells opt into tabular figures. */
.pp-table__number { font-variant-numeric: tabular-nums; text-align: end; }

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

   Square at the full control height, so a 20 px glyph still gets a 44 px target. */

.pp-icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--control-height);
  block-size: var(--control-height);
  min-inline-size: var(--touch-target-min);
  min-block-size: var(--touch-target-min);
  padding: 0;
  border: var(--border-width-hairline) solid transparent;
  border-radius: var(--radius-md);
  background-color: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-standard),
              color var(--motion-fast) var(--ease-standard),
              border-color var(--motion-fast) var(--ease-standard);
}

.pp-icon-button:disabled { opacity: var(--opacity-disabled); cursor: default; }
.pp-icon-button--tertiary:hover:not(:disabled) { background-color: var(--surface-sunken); color: var(--text-primary); }
.pp-icon-button--secondary { border-color: var(--border-strong); background-color: var(--surface-default); color: var(--text-primary); }
.pp-icon-button--secondary:hover:not(:disabled) { background-color: var(--surface-sunken); }
.pp-icon-button--primary { background-color: var(--accent-default); color: var(--text-on-accent); }
.pp-icon-button--primary:hover:not(:disabled) { background-color: var(--accent-hover); }
.pp-icon-button--danger { color: var(--danger-default); }
.pp-icon-button--danger:hover:not(:disabled) { background-color: var(--surface-sunken); }

/* Small stays at the minimum touch target even though the box shrinks visually. */
.pp-icon-button--small { inline-size: var(--control-height-sm); block-size: var(--control-height-sm); }
.pp-icon-button--large { inline-size: var(--control-height-lg); block-size: var(--control-height-lg); }

/* ---------------------------------------------------------------- card states */

.pp-card--loading { cursor: progress; }
/* The content is stale while loading, so it is muted, but never hidden: a card that
   empties itself loses its height and the page jumps. */
.pp-card--loading > * { opacity: var(--opacity-muted); }

.pp-card--disabled { opacity: var(--opacity-disabled); cursor: default; }
.pp-card--disabled:hover { transform: none; box-shadow: none; }

/* ---------------------------------------------------------------- search input */

.pp-search { position: relative; display: flex; align-items: center; }
.pp-search__icon {
  position: absolute;
  inset-inline-start: var(--space-3);
  color: var(--text-placeholder);
  pointer-events: none;
  line-height: 0;
}
/* Leaves room for the icon without the text ever sliding under it. */
.pp-search .pp-input { padding-inline-start: calc(var(--space-3) * 2 + var(--icon-md)); }

/* ---------------------------------------------------------------- motion primitives

   Reusable entrances, prepared for ACP-DESIGN-001B. No page uses them yet, and none
   is page-specific: each is a single property change on the existing motion scale,
   with no bounce, spring or overshoot anywhere (DL §9).

   Every one collapses under prefers-reduced-motion via the global rule in base.css,
   and each ends at a visible state so a collapsed animation never leaves an element
   stuck at zero opacity. */

.pp-motion-fade-in { animation: pp-fade-in var(--motion-base) var(--ease-enter) both; }
.pp-motion-rise    { animation: pp-rise-in var(--motion-base) var(--ease-enter) both; }
.pp-motion-settle  { animation: pp-settle-in var(--motion-slow) var(--ease-standard) both; }
.pp-motion-draw    { animation: pp-stroke-draw var(--motion-ceremony) var(--ease-standard) both; }

/* Staggering children by index, for a list that appears as a group rather than at once. */
.pp-motion-stagger > * { animation: pp-rise-in var(--motion-base) var(--ease-enter) both; }
.pp-motion-stagger > *:nth-child(1) { animation-delay: 0ms; }
.pp-motion-stagger > *:nth-child(2) { animation-delay: 40ms; }
.pp-motion-stagger > *:nth-child(3) { animation-delay: 80ms; }
.pp-motion-stagger > *:nth-child(4) { animation-delay: 120ms; }
.pp-motion-stagger > *:nth-child(n+5) { animation-delay: 160ms; }

/* pp-fade-in and pp-rise-in already exist above and are used by the banner, the toast and the upload
   zone. They are REUSED here rather than redefined: a second @keyframes block with the same name
   silently overrides the first for every existing caller, which is a defect that only surfaces once
   someone changes one of the two copies.

   Only the genuinely new movements are declared, under names nothing else uses. */

@keyframes pp-settle-in {
  from { opacity: 0; transform: translateY(calc(var(--space-2) * -1)); }
  to   { opacity: var(--opacity-full); transform: translateY(0); }
}

/* Generic stroke reveal for ACP-DESIGN-001B. Distinct from pp-draw-check, which is the completion
   tick and carries the ceremony timing that belongs to that one moment. */
@keyframes pp-stroke-draw {
  from { stroke-dashoffset: var(--pp-draw-length, 100); }
  to   { stroke-dashoffset: 0; }
}

/* The one-line notice under the hero actions in local demo mode. Caption weight, secondary colour:
   it explains, it does not compete with the headline. */
.pp-landing__demo-note {
  color: var(--text-secondary);
  max-width: var(--measure-prose);
  margin: var(--space-2) 0 0;
}

/* ---------------------------------------------------------------- sign-in methods (ACP-AUTH-001)

   A column of full-width actions rather than a row. Three methods side by side make each one look
   like a variant of the others; stacked, each is a decision, and the widest label does not decide
   the width of the rest. */

.pp-authmethods {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: var(--container-reading);
}

.pp-authmethods__item { width: 100%; }

/* Consent rows. The checkbox and its label share a baseline and the whole row is the label, so the
   target is the sentence rather than a 16px square. */
.pp-consent {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: var(--measure-prose);
}

.pp-consent__row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  cursor: pointer;
  /* WCAG 2.2 AA 2.5.8: the row is the target, and it clears 24px on its own. */
  min-height: var(--touch-target-compact);
}

.pp-consent__row input[type="checkbox"] {
  margin-block-start: var(--space-1);
  inline-size: var(--icon-sm);
  block-size: var(--icon-sm);
  flex: none;
  accent-color: var(--accent-default);
}

/* The optional permission is set apart from the required ones by a rule, not by colour alone. */
.pp-consent__row--optional {
  padding-block-start: var(--space-3);
  border-top: var(--border-width-hairline) solid var(--border-default);
  color: var(--text-secondary);
}

/* The registration gate, expressed in CSS so the page needs no circuit.

   The method buttons appear only once BOTH required boxes are ticked, and the prompt that explains
   why disappears at the same moment. :has() reads the live checked state, so this needs no script and
   no interactive render mode — which matters, because an interactively rendered form cannot emit an
   antiforgery token and would be refused by the server on submit.

   This is presentation only. The server reads the posted acknowledgements and refuses without them,
   so on a browser without :has() the buttons are simply visible from the start and pressing one
   returns the customer here. Nothing about the rule depends on this file. */
.pp-consent-form__methods { display: none; }

.pp-consent-form:has(#pp-consent-terms:checked):has(#pp-consent-kvkk:checked) .pp-consent-form__methods {
  display: revert;
}

.pp-consent-form:has(#pp-consent-terms:checked):has(#pp-consent-kvkk:checked) .pp-authmethods.pp-consent-form__methods {
  display: flex;
}

.pp-consent-form:has(#pp-consent-terms:checked):has(#pp-consent-kvkk:checked) .pp-consent-form__pending {
  display: none;
}

@supports not selector(:has(*)) {
  .pp-consent-form__methods { display: revert; }
  .pp-authmethods.pp-consent-form__methods { display: flex; }
  .pp-consent-form__pending { display: none; }
}

/* ---------------------------------------------------------------- development bar (ACP-DEV-001)

   A slim strip naming the environment, rendered only when the local demo is active. It exists so a
   screenshot of synthetic data cannot be mistaken for Production.

   Deliberately restrained. A full-width red banner would dominate every screenshot it appears in
   and would defeat the purpose of reviewing the design — this is a hairline strip in the warning
   colour, one line tall, above the header.

   It participates in normal flow rather than floating: a fixed strip would sit over the header on
   every page and change what is being reviewed. One line of height is a layout difference the
   reviewer can account for; an overlay is not. */

.pp-devbar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding-block: var(--space-1);
  padding-inline: var(--page-margin-mobile);
  color: var(--text-secondary);
  background-color: var(--surface-sunken);
  border-bottom: var(--border-width-hairline) solid var(--warning-default);
}

.pp-devbar__dot {
  inline-size: var(--space-2);
  block-size: var(--space-2);
  border-radius: var(--radius-full);
  background-color: var(--warning-default);
  flex: none;
}

.pp-devbar__label { color: var(--warning-default); }

/* The scenario name is the second-most useful thing here and the first to go when the viewport is
   narrow — the environment name is what must survive. */
.pp-devbar__detail {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pp-devbar__link { margin-inline-start: auto; color: var(--text-secondary); }
.pp-devbar__link:hover { color: var(--accent-default); }

@media (max-width: 767px) {
  .pp-devbar__detail { display: none; }
}

/* Never in print. A printed page carrying a development strip is a printed page that will be
   photographed and misread. */
@media print {
  .pp-devbar { display: none; }
}

/* ---------------------------------------------------------------- ribbon schematic (ACP-AUTOCAD-001B)

   A drawing of the AutoCAD ribbon tab the add-in installs, on the product page. Deliberately a
   line drawing rather than a screenshot: no screenshot of this product exists yet, and a mocked-up
   one presented as a screenshot is a fabricated record of software behaviour.

   currentColor throughout, so the schematic inherits the theme instead of carrying a palette. The
   figure sets the secondary text colour and the drawing follows it — one declaration, both themes. */

.pp-ribbon {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  color: var(--text-secondary);
}

.pp-ribbon__svg {
  width: 100%;
  height: auto;
  /* Below this the 640-unit drawing renders its labels smaller than the smallest readable size, so
     it scrolls rather than shrinking further — the same rule the wide tables follow. */
  min-width: var(--container-schematic-min);
  border: var(--border-width-hairline) solid var(--border-default);
  border-radius: var(--radius-md);
  background-color: var(--surface-sunken);
  padding: var(--space-2);
}

/* The drawing is wider than a narrow phone. Scroll it inside its own box; the page body must never
   scroll horizontally. */
.pp-ribbon { overflow-x: auto; }

/* ---------------------------------------------------------------- ultra-wide

   Above the app container the page stops growing and centres. Line lengths beyond
   about 90 characters cost reading speed, so extra width becomes margin. */

@media (min-width: 1600px) {
  .pp-container { max-width: var(--container-ultrawide); }
}
.pp-commerce{max-width:880px;margin:0 auto;padding:var(--space-8) 0;display:grid;gap:var(--space-6)}
.pp-commerce__card{padding:var(--space-6)}
.pp-commerce__summary{display:grid;gap:var(--space-3);margin:0}
.pp-commerce__summary div{display:grid;grid-template-columns:minmax(10rem,1fr) 2fr;gap:var(--space-4);padding-block:var(--space-3);border-bottom:1px solid var(--border-default)}
.pp-commerce__summary dt{font-weight:650}.pp-commerce__summary dd{margin:0}
.pp-commerce__acceptance{display:grid;gap:var(--space-4);padding:var(--space-5);border:1px solid var(--border-default);border-radius:var(--radius-lg)}
.pp-commerce__acceptance label{display:flex;gap:var(--space-3);align-items:flex-start}
.pp-commerce__actions{display:flex;flex-wrap:wrap;gap:var(--space-3);justify-content:space-between}
.pp-commerce__discount dd{color:var(--success-text);font-weight:650}
.pp-payment-method{display:grid;gap:var(--space-4)}
.pp-payment-method__brands{display:flex;flex-wrap:wrap;gap:var(--space-3)}
.pp-payment-method__brands span{min-width:7rem;padding:.7rem 1rem;border:1px solid var(--border-default);border-radius:var(--radius-md);background:var(--surface-sunken);color:var(--text-primary);font-weight:700;letter-spacing:.02em;text-align:center}
.pp-commerce__coupon{display:grid;gap:var(--space-3);padding:var(--space-5);border:1px solid var(--border-default);border-radius:var(--radius-lg)}
.pp-commerce__coupon>div{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--space-3)}
.pp-commerce__coupon input{min-width:0;width:100%;padding:.75rem 1rem;border:1px solid var(--border-default);border-radius:var(--radius-md);background:var(--surface-raised);color:var(--text-primary)}
.pp-commerce__coupon-success{margin:0;color:var(--success-text);font-weight:650}.pp-commerce__coupon-error{margin:0;color:var(--danger-text)}
@media(max-width:640px){.pp-commerce__summary div{grid-template-columns:1fr;gap:var(--space-1)}.pp-commerce__actions>*{width:100%;justify-content:center}.pp-commerce__coupon>div{grid-template-columns:1fr}.pp-commerce__coupon .pp-button{width:100%;justify-content:center}}
.pp-admin-discounts{display:grid;gap:var(--space-7);padding:var(--space-8) 0}.pp-admin-discounts__create,.pp-admin-discounts__program,.pp-admin-discounts__revoke{padding:var(--space-6)}
.pp-admin-discounts__form{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-4)}.pp-admin-discounts label{display:grid;gap:var(--space-2)}
.pp-admin-discounts input{min-width:0;padding:.7rem .85rem;border:1px solid var(--border-default);border-radius:var(--radius-md);background:var(--surface-raised);color:var(--text-primary)}
.pp-admin-discounts__packages{display:flex;flex-wrap:wrap;gap:var(--space-4);margin:var(--space-5) 0;padding:var(--space-4);border:1px solid var(--border-default);border-radius:var(--radius-lg)}.pp-admin-discounts__packages label{display:flex;align-items:center;gap:var(--space-2)}
.pp-admin-discounts__list{display:grid;gap:var(--space-4)}.pp-admin-discounts__program>header{display:flex;justify-content:space-between;gap:var(--space-4)}.pp-admin-discounts__program>header div{display:grid;gap:var(--space-1)}
.pp-admin-discounts__program dl{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--space-3)}.pp-admin-discounts__program dl div{display:grid;gap:var(--space-1)}.pp-admin-discounts__program dd{margin:0;font-weight:650}
.pp-admin-discounts__actions{display:flex;flex-wrap:wrap;align-items:end;gap:var(--space-3)}.pp-admin-discounts__actions label{max-width:10rem}.pp-admin-discounts__revoke>div{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--space-3)}
@media(max-width:720px){.pp-admin-discounts__form{grid-template-columns:1fr}.pp-admin-discounts__program dl{grid-template-columns:repeat(2,minmax(0,1fr))}.pp-admin-discounts__revoke>div{grid-template-columns:1fr}.pp-admin-discounts__actions>*{width:100%}}
@media(max-width:480px){.pp-account .pp-nav__link:nth-of-type(2),.pp-account .pp-badge,.pp-account__initials{display:none}.pp-header__inner{gap:var(--space-2)}.pp-account{gap:var(--space-1)}.pp-account .pp-nav__link{padding-inline:var(--space-2)}}

/* ---------------------------------------------------------------- Corporate discount CTA
   A floating panel on desktop, an ordinary card on narrow screens. The brief asked for a slowly
   travelling glow on the border; the restraint is deliberate, because the difference between an
   enterprise feature and an advert here is almost entirely amplitude.

   The light travels on a conic-gradient held in a pseudo element behind the surface, not on the card
   itself: only the 1px rim is painted, the background never pulses, and the text never moves. One
   compositor-friendly rotation of a single custom property, no JS timer, no canvas.

   @property lets the browser interpolate the angle smoothly. Where it is unsupported the rule is
   simply ignored, the animation falls back to a step-wise rotation that still reads as travelling, and
   nothing breaks. */
@property --pp-corp-angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

/*
   In flow, right-aligned, directly above the footer.

   THE MOBILE BUG THIS FIXES. This was position:fixed on desktop and position:static below 767px.
   Fixed makes the card a containing block for its absolutely positioned __glow; static does not. So
   on a phone the glow kept position:absolute but lost its containing block, resolved against the
   initial containing block instead, and painted a conic-gradient the size of the viewport — with a
   blurred ::after copy on top of it. The result was a full-screen red field with the real card sitting
   separately near the footer. isolation:isolate did not help: it creates a stacking context, not a
   containing block.

   position:relative is the fix, and it is the same value at every width, so the containing block can
   no longer disappear underneath the glow. Being in flow also gives the owner what the fixed version
   could never do — alignment with the footer's top boundary rather than with the viewport's bottom
   edge — and removes the possibility of covering page content at any size.
*/
/*
   A compact HORIZONTAL rectangle, about 1.8:1. The first compact pass shrank the width but kept the
   old vertical rhythm, which produced a near-square 250x224 mini-card — the wrong shape. The width now
   carries the headline on one line and the height is governed by the type scale below, so the card
   reads as a small banner rather than a tall tile.
*/
.pp-corp-cta {
  position: relative;
  inline-size: 272px;
  max-inline-size: 100%;
  border-radius: var(--radius-md);
  isolation: isolate;
}

/* The travelling rim. Sits one pixel outside the surface and is masked to a ring by the surface that
   covers it, so no expensive mask compositing is needed. */
.pp-corp-cta__glow {
  position: absolute;
  inset: -1px;                 /* the rim, revealed around the surface that sits on top of it */
  border-radius: inherit;
  background:
    conic-gradient(from var(--pp-corp-angle),
      var(--accent-pressed) 0deg,
      var(--accent-default) 90deg,
      var(--accent-gradient-end) 150deg,
      var(--accent-pressed) 240deg,
      var(--accent-pressed) 360deg);
  animation: pp-corp-travel 8s linear infinite;
  pointer-events: none;
}

/* A second, blurred copy of the same sweep: this is what reads as "glow" rather than "coloured line".
   Kept low so the card never looks neon. */
.pp-corp-cta__glow::after {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  background: inherit;
  filter: blur(9px);
  opacity: .28;
  transition: opacity var(--motion-base) var(--ease-standard);
}

.pp-corp-cta:hover .pp-corp-cta__glow::after { opacity: .42; }

@keyframes pp-corp-travel {
  to { --pp-corp-angle: 360deg; }
}

.pp-corp-cta__surface {
  position: relative;
  border-radius: inherit;
  padding: var(--space-2) var(--space-3);
  background-color: var(--surface-raised);
  box-shadow: var(--elevation-3);
  overflow: hidden;
}

/* The action, sized for the card rather than for a page. PpButton's small size is tuned for forms;
   inside a 145px-tall banner its default padding is most of the remaining height. */
.pp-corp-cta__surface .pp-button {
  padding-block: var(--space-1);
  font-size: var(--type-caption-strong-size);
  white-space: nowrap;
}

/* The approved O/ring mark, barely there. It gives the card a brand anchor without another asset. */
.pp-corp-cta__watermark {
  position: absolute;
  inset-block-start: -12px;
  inset-inline-end: -18px;
  inline-size: 96px;
  color: var(--accent-default);
  opacity: .05;
  pointer-events: none;
}

.pp-corp-cta__close {
  position: absolute;
  inset-block-start: var(--space-1);
  inset-inline-end: var(--space-1);
  display: inline-flex;
  padding: var(--space-1);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
}

.pp-corp-cta__close svg { inline-size: 14px; block-size: 14px; }
.pp-corp-cta__close:hover { color: var(--text-primary); background-color: var(--surface-sunken); }

/* The type scale steps down with the card. Nothing drops below caption-strong (12px), which is the
   smallest size the system already ships as readable body-adjacent text.

   Line heights are set tighter than the tokens' defaults because those are tuned for running prose,
   and four stacked blocks at prose leading are what made the card tall. The sizes themselves are
   unchanged token values, so nothing is shrunk below what the system considers readable. */
.pp-corp-cta__eyebrow {
  margin: 0 0 var(--space-1);
  color: var(--accent-default);
  font-size: var(--type-caption-strong-size);
  line-height: 1.2;
  font-weight: var(--weight-strong);
  letter-spacing: .08em;
}

/* One line at the card's width in Turkish, which is the headline the geometry was designed around:
   it measures 224px against 232px of content box. The 15px body size wrapped it in two, which cost a
   whole line of height and made the card read as a paragraph rather than a title.

   Deliberately NOT text-wrap: nowrap. Forcing one line did hold the Turkish headline, but the English
   one is 266px — 34px wider than the box — so nowrap combined with the surface's overflow:hidden
   silently cut the end of it off. A headline that wraps is compact; a headline that is invisibly
   truncated is broken, so English takes a second line and the card grows by one line-height for that
   locale only. */
.pp-corp-cta__title {
  margin: 0 0 var(--space-1);
  font-size: var(--type-caption-size);
  line-height: 1.35;
  font-weight: var(--weight-strong);
  color: var(--text-primary);
}

.pp-corp-cta__body {
  margin: 0 0 var(--space-2);
  font-size: var(--type-caption-strong-size);
  line-height: 1.35;
  color: var(--text-secondary);
}

.pp-corp-modal__fields {
  display: grid;
  gap: var(--space-3);
  margin-block-start: var(--space-4);
}

.pp-corp-modal__note { resize: vertical; min-block-size: 72px; font-family: inherit; }

/* Narrow viewports: the card gives up its fixed 250px and spans the container instead. It is already
   in flow at every width, so nothing about positioning changes here.

   position is deliberately NOT restated. Setting it to static was the defect: the glow is absolutely
   positioned, and a static parent is not a containing block, so the glow escaped to the viewport and
   painted the whole screen red. Leaving position:relative to inherit from the base rule is the fix,
   and omitting it here is what keeps it fixed. 767px is the breakpoint the rest of the site uses. */
@media (max-width: 767px) {
  /* On a phone the overlay is not safe. The desktop hero has empty drawing at its lower right; the
     narrow one does not — the same band carries "Neden yalnızca PLT?" and the demo strip, and a
     132px card pinned there sits on top of both. So the dock returns to flow at the bottom of main,
     below the drawing and above the footer, where it covers nothing.

     This is a positioning change on the DOCK only. The card itself stays position:relative at every
     width, which is what keeps the glow's containing block — the whole point of the mobile fix. */
  .pp-corp-dock {
    position: static;
    padding-block: var(--space-4) var(--space-2);
  }

  .pp-corp-cta { inline-size: auto; }
}

/* Reduced motion: keep the rim, drop the travel. The card should still look finished, not switched off. */
@media (prefers-reduced-motion: reduce) {
  .pp-corp-cta__glow {
    animation: none;
    background: linear-gradient(140deg, var(--accent-pressed), var(--accent-default), var(--accent-pressed));
  }

  .pp-corp-cta__glow::after { opacity: .2; }
  .pp-corp-cta:hover .pp-corp-cta__glow::after { opacity: .2; }
}

/* High contrast: the glow is decoration and cannot be relied on, so give the card a real border. */
@media (forced-colors: active) {
  .pp-corp-cta__surface { border: 1px solid CanvasText; }
  .pp-corp-cta__glow { display: none; }
}

/* ---------------------------------------------------------------------------
   New-account welcome benefit (PLOTPDFPRO-SITE-NEW-ACCOUNT-5-CREDIT-GRANT-001)

   A compact callout beside the sign-in and registration choices, not a banner and
   not a card. It sits in the accent-subtle surface with a hairline accent border,
   which is the quietest way the system has to say "this is worth reading" without
   competing with the primary button directly beneath it.

   Semantic tokens only. Component styles may not reference primitive tokens, and a
   test enforces that.
   --------------------------------------------------------------------------- */
.pp-welcome-grant {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-3);
  border: var(--border-width-hairline) solid var(--accent-border);
  border-radius: var(--radius-md);
  background: var(--accent-subtle);
}

.pp-welcome-grant__headline {
  margin: 0;
  font-size: var(--type-caption-strong-size);
  line-height: var(--type-caption-strong-line);
  font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-caption-strong);
  /* accent-hover, not accent-pressed, and the reason is contrast rather than state.
     Components here theme purely through tokens — none overrides itself on data-theme — so this one
     value has to clear AA on the accent-subtle ground in BOTH themes. Measured against it:
     accent-pressed 8.45:1 light but 3.07:1 dark, accent-default 4.93 / 3.87, accent-hover 6.45 / 5.28.
     accent-hover is the only value in the ramp that passes both, and it keeps the headline reading as
     a benefit rather than as ordinary body copy in a tinted box. */
  color: var(--accent-hover);
}

.pp-welcome-grant__body {
  margin: 0;
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
  color: var(--text-secondary);
}

/* In dark chrome accent-pressed is the lighter end of the ramp, so the headline
   keeps its contrast against the subtle accent ground without a second rule. */

/*
  PAYTR-002. The provider's payment frame.

  It lives in the stylesheet rather than on the element because the inline-style inventory is a
  security control: every style attribute in the product is counted by a test, and the CSP tolerates
  them as a known, fixed set rather than as a habit.
*/
/*
  PAYTR-IFRAME-RESIZER-001A. The provider's resizer sets the real height once its hosted form has
  loaded; this is only somewhere for the frame to be while that happens.

  It used to be 40rem, and that was not a placeholder — it was the height the frame kept forever,
  because an iframe never grows to fit its content. The card block filled the visible part, the pay
  button sat below the cut, and scrolling was off by the provider's own instruction, so there was no
  way to reach it. The value is now small enough to read as "loading" and low enough that it cannot
  hold a shorter provider page open.
*/
.pp-commerce__payment-frame {
    width: 100%;
    min-height: 12rem;
    border: 0;
}

/* PRE-ADS-HOTFIX-001: compact Basic Consent bar with an explicit, expandable preference layer. */
.pp-consent {
  position: fixed;
  inset-inline: max(var(--space-3), env(safe-area-inset-left)) max(var(--space-3), env(safe-area-inset-right));
  inset-block-end: max(var(--space-3), env(safe-area-inset-bottom));
  z-index: 1200;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-3);
  max-inline-size: 64rem;
  max-block-size: calc(100vh - (2 * var(--space-3)));
  margin-inline: auto;
  padding: var(--space-3);
  border: var(--border-width-hairline) solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface-raised);
  box-shadow: var(--elevation-3);
  color: var(--text-primary);
  overflow-y: auto;
}

.pp-consent[hidden] { display: none; }
.pp-consent__summary { display: grid; gap: calc(var(--space-1) / 2); }
.pp-consent__summary p {
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--type-caption-size);
}
.pp-consent__summary .pp-link { margin-inline-start: var(--space-1); }
.pp-consent__actions { display: flex; flex: 0 0 auto; gap: var(--space-2); }
.pp-consent__actions .pp-button { white-space: nowrap; }

.pp-consent__settings {
  grid-column: 1 / -1;
  display: grid;
  gap: var(--space-2);
  padding-block-start: var(--space-3);
  border-block-start: var(--hairline) solid var(--border-default);
}
.pp-consent__settings[hidden] { display: none; }
.pp-consent__preference {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-3);
}
.pp-consent__preference p {
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--type-caption-size);
}
.pp-consent__switch {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--touch-target-compact);
  color: var(--text-secondary);
  font-size: var(--type-caption-size);
  cursor: pointer;
}
.pp-consent__switch input { inline-size: 1.125rem; block-size: 1.125rem; accent-color: var(--accent-default); }
.pp-consent__switch--locked { cursor: default; }
.pp-consent__settings-actions { display: flex; justify-content: flex-end; gap: var(--space-2); }

@media (max-width: 767px) {
  .pp-consent {
    grid-template-columns: minmax(0, 1fr);
    align-items: stretch;
    inset-inline: max(var(--space-2), env(safe-area-inset-left)) max(var(--space-2), env(safe-area-inset-right));
    inset-block-end: max(var(--space-2), env(safe-area-inset-bottom));
  }
  .pp-consent__actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pp-consent__actions .pp-button { inline-size: 100%; min-inline-size: 0; white-space: normal; }
  .pp-consent__actions .pp-button:first-child { grid-column: 1 / -1; }
  .pp-consent__preference { grid-template-columns: minmax(0, 1fr); gap: var(--space-1); }
  .pp-consent__settings-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pp-consent__settings-actions .pp-button { min-inline-size: 0; }
}
