:root{color-scheme:light;--p-bg:var(--brand-bg);--p-card:var(--brand-surface);--p-text:var(--brand-text);--p-muted:var(--brand-muted);--p-border:var(--brand-line);--p-accent:var(--brand-accent);--p-soft:var(--brand-soft);--p-success:var(--brand-success);--p-success-soft:#e8f1e8;--p-warn:#916735;--p-warn-soft:#f8f1e3;--p-caution:#7d5300;--p-caution-soft:#fff5d6;--p-caution-edge:#e0a91d;--p-danger:#a74946;--p-shadow:var(--brand-shadow)}
:root[data-theme=dark]{color-scheme:dark;--p-bg:var(--brand-bg);--p-card:var(--brand-surface);--p-text:var(--brand-text);--p-muted:var(--brand-muted);--p-border:var(--brand-line);--p-accent:var(--brand-accent);--p-soft:var(--brand-soft);--p-success:var(--brand-success);--p-success-soft:#273e30;--p-warn:#ddc090;--p-warn-soft:#3b3326;--p-caution:#ffd87a;--p-caution-soft:#3f3208;--p-caution-edge:#8f6d12;--p-danger:#efa5a0;--p-shadow:var(--brand-shadow)}
*{box-sizing:border-box}body{margin:0;background:var(--p-bg);color:var(--p-text);font:15px/1.6 var(--font-sans);min-height:100dvh;display:flex;flex-direction:column}button,input,select,textarea{font:inherit}button,a,input,select,textarea{-webkit-tap-highlight-color:transparent}a{color:inherit}button,a,select{touch-action:manipulation}button{cursor:pointer}button:disabled{opacity:.55;cursor:not-allowed}button,input,select,textarea{border-radius:11px}button{border:1px solid var(--p-border);padding:12px 18px;font-weight:650;color:var(--p-text);background:var(--p-card)}button:not(:disabled):hover{filter:brightness(.96);transform:translateY(-1px)}button:active{transform:translateY(0)}:focus,:focus-visible{outline:none}[hidden]{display:none!important}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.skip{position:absolute;top:-100px;left:16px;z-index:100;background:var(--p-card);padding:12px}.skip:focus{top:12px}.header{width:min(var(--p-measure),100%);margin:0 auto;padding:28px 32px;display:flex;align-items:center;justify-content:space-between;gap:20px}.brand{display:flex;gap:12px;align-items:center;text-decoration:none;font-size:18px;font-weight:750;letter-spacing:-.4px}.brand small{display:block;font-size:9px;letter-spacing:1.65px;font-weight:600;color:var(--p-muted);line-height:1.4}.preferences{display:flex;gap:9px;align-items:center}.preferences select{padding:9px;background:var(--p-card);border:1px solid var(--p-border);color:var(--p-text);max-width:110px}.icon-button{width:43px;height:43px;padding:0;font-size:22px}.main{width:min(var(--p-measure),100%);padding:25px 32px 0;margin:0 auto;flex:1}.eyebrow{font-size:10px;letter-spacing:2px;font-weight:750;color:var(--p-accent)}h1,h2,.eyebrow{font-family:var(--font-display)}h1{font-size:clamp(27px,4vw,39px);line-height:1.22;letter-spacing:-1.1px;margin:10px 0 12px}h2{font-size:20px;line-height:1.35;margin:0}.hint,.privacy,footer{color:var(--p-muted)}.tabs{display:grid;grid-template-columns:repeat(3,1fr);gap:4px;padding:5px;background:var(--p-card);border:1px solid var(--p-border);border-radius:14px;margin-bottom:24px}.tabs a{text-decoration:none;text-align:center;font-size:13px;font-weight:650;border-radius:9px;padding:12px 8px;transition:background var(--motion-base) var(--ease-out),color var(--motion-base) var(--ease-out)}.tabs a[aria-current=page]{background:var(--p-soft);color:var(--p-accent)}.steps{display:flex;list-style:none;gap:24px;padding:0;margin:0 0 20px}.steps li{display:flex;align-items:center;gap:10px;flex:1;color:var(--p-muted);font-size:12px}.steps li span{width:28px;height:28px;border:1px solid var(--p-border);display:grid;place-items:center;border-radius:9px;flex-shrink:0}.steps .current{color:var(--p-accent)}.steps .current span{background:var(--p-soft);border-color:var(--p-accent)}.steps .done span{background:var(--p-success-soft);color:var(--p-success);border-color:var(--p-success)}.panel{background:var(--p-card);border:1px solid var(--p-border);border-radius:17px;padding:28px;box-shadow:var(--p-shadow);margin-bottom:20px}.panel label{display:block;font-size:13px;font-weight:650;margin-bottom:8px}input:not([type=checkbox]),textarea{display:block;width:100%;color:var(--p-text);background:var(--p-bg);border:1px solid var(--p-border);padding:13px 14px}textarea{resize:vertical;max-height:250px;min-height:120px;font:13px/1.65 ui-monospace,Consolas,monospace}input::placeholder,textarea::placeholder{color:var(--p-muted);opacity:.7}.hint{font-size:12px;margin:12px 0 20px}.hint.faint{font-size:11px;opacity:.62;margin:-14px 0 18px}.primary{background:var(--brand-action);border-color:var(--brand-action);color:var(--brand-on-action);display:flex;align-items:center;justify-content:space-between;gap:20px;width:100%;min-height:48px}.secondary{background:var(--p-soft);color:var(--p-accent);width:100%;min-height:46px}.error{font-size:13px;color:var(--p-danger);margin:12px 0 0}.error:empty{display:none}.plan-banner{background:var(--p-soft);padding:16px;border-radius:12px;display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:24px}.plan-banner span{color:var(--p-muted);font-size:11px;display:block}.plan-banner strong{font-size:20px;color:var(--p-accent);font-variant-numeric:tabular-nums}.text-button{background:none;border:0;padding:6px 8px;margin:-6px -8px;min-height:32px;color:var(--p-accent);font-size:12px;white-space:nowrap}.details{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));margin:18px 0 0;gap:0}.detail{margin:0;padding:14px 0;border-top:1px solid var(--p-border);min-width:0}.detail:nth-child(odd){padding-right:18px}.detail dt{font-size:11px;color:var(--p-muted);margin-bottom:4px}.detail dd{margin:0;font-size:13px;font-weight:600;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.confirm-warning{display:flex;align-items:flex-start;gap:11px;margin:22px 0;padding:14px 16px;font-size:13px;line-height:1.5;font-weight:650;border-radius:12px;color:var(--p-caution);background:var(--p-caution-soft);border:1px solid var(--p-caution-edge);border-left-width:5px}.confirm-warning .ui-icon{width:18px;height:18px;flex-shrink:0;margin-top:1px}.result-heading{display:flex;align-items:center;gap:13px}.result-heading small{font-size:9px;letter-spacing:1.3px;font-weight:700;color:var(--p-muted)}.status-icon{height:38px;width:38px;border-radius:50%;display:grid;place-items:center;flex-shrink:0;background:var(--p-soft);color:var(--p-accent);font-size:22px}.result[data-state=succeeded] .status-icon{background:var(--p-success-soft);color:var(--p-success)}.result[data-state=operator_required] .status-icon,.result[data-state=account_error] .status-icon{background:var(--p-warn-soft);color:var(--p-warn)}.result-copy{font-size:13px;color:var(--p-muted);margin:20px 0 0}.live-badge,.badge{font-size:10px;line-height:1.3;color:var(--p-success);border-radius:20px;padding:7px 10px;background:var(--p-success-soft);margin-left:auto;white-space:nowrap}.live-badge::before{content:'●';font-size:7px;margin-right:6px}.result:not([data-state=processing]):not([data-state=manual_review]):not([data-state=operator_required]):not([data-state=account_error]) .live-badge{display:none}.sync-note:empty{display:none}.section-heading{display:flex;align-items:center;gap:12px}.privacy{display:flex;gap:9px;justify-content:center;font-size:11px;line-height:1.7;margin:24px 8px 28px}.privacy span:first-child{font-size:18px}.view{animation:enter var(--motion-page) var(--ease-out)}footer{display:flex;justify-content:space-between;gap:15px;width:min(var(--p-measure),100%);margin:20px auto 0;padding:22px 32px;border-top:1px solid var(--p-border);font-size:11px}.busy{cursor:progress!important}.busy .ui-icon{display:none}.busy::after{content:'';height:14px;width:14px;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spin 1s linear infinite;display:inline-block;margin-left:10px;vertical-align:middle;flex-shrink:0}@keyframes spin{to{transform:rotate(360deg)}}@keyframes enter{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}@media(max-width:600px){.header{padding:20px 18px}.brand{font-size:15px;gap:9px}.brand small{font-size:8px;letter-spacing:1px}.preferences{gap:6px}.preferences select{font-size:12px;width:85px}.icon-button{width:36px;height:38px}.main{padding:18px 18px 0}.panel{padding:20px;border-radius:14px}.tabs a{font-size:11px;padding:11px 4px}.steps{gap:10px}.steps li{font-size:11px;gap:7px}.details{grid-template-columns:1fr}.detail:nth-child(odd){padding-right:0}.result-heading{flex-wrap:wrap;gap:9px}.result-heading h2{font-size:18px}.result-heading .live-badge{margin:8px 0 0 47px}.plan-banner{padding:12px}.plan-banner strong{font-size:18px}footer{padding:20px 18px;font-size:10px}.privacy{margin:20px 3px}.section-heading h2{font-size:18px}}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}.busy::after{border-style:dotted}}

/* Quiet material and consistent movement across the owner and activation views. */
.panel{border-radius:18px}.tabs a[aria-current=page]{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--p-accent) 12%,transparent)}.primary{box-shadow:0 4px 10px #243b2b0a}.privacy .ui-icon{width:17px;height:17px;margin-top:1px}.preferences .ui-icon{width:19px;height:19px}

/* Public activation flow: compact steps, contextual help, and explicit review. */
.main{padding-top:14px;padding-bottom:28px;max-width:var(--p-measure)}.brand{letter-spacing:-.5px}.tabs{margin-bottom:30px}.tabs a{transition:background-color var(--motion-base) var(--ease-out),color var(--motion-base) var(--ease-out),box-shadow var(--motion-base) var(--ease-out),transform var(--motion-base) var(--ease-out)}.tabs a:hover{background:var(--p-soft)}
.steps{gap:18px;margin:0 4px 24px}.steps li{position:relative;gap:9px;align-items:flex-start;line-height:1.4}.steps li b{padding-top:6px;font-weight:600}.steps li span{background:var(--p-card);width:31px;height:31px;border-radius:50%;transition:background-color var(--motion-base) var(--ease-out),border-color var(--motion-base) var(--ease-out),color var(--motion-base) var(--ease-out)}.steps .done{color:var(--p-success)}.steps .current span{box-shadow:0 0 0 4px color-mix(in srgb,var(--p-accent) 8%,transparent)}
#account-step,#code-form,#review-account-wrap,.result{animation:enter var(--motion-page) var(--ease-out)}.plan-banner{background:linear-gradient(120deg,var(--p-soft),var(--p-card));margin-bottom:20px}.token-guide{display:grid;grid-template-columns:minmax(0,1fr) 20px minmax(0,1fr);align-items:center;gap:10px}.token-link{display:flex;align-items:center;gap:9px;text-decoration:none;font-size:13px;font-weight:650;border:1px solid var(--p-border);border-radius:12px;padding:14px 12px;background:var(--p-card);min-width:0;transition:background-color var(--motion-base) var(--ease-out),border-color var(--motion-base) var(--ease-out),transform var(--motion-base) var(--ease-out),box-shadow var(--motion-base) var(--ease-out)}.token-link span{flex:1;line-height:1.4}.token-link:hover{background:var(--p-soft);border-color:var(--p-accent);box-shadow:0 4px 12px #243b2b09;transform:translateY(-2px)}.token-link.is-disabled{cursor:not-allowed;opacity:.62;color:var(--p-muted);background:var(--p-bg);box-shadow:none}.token-link.is-disabled:hover{background:var(--p-bg);border-color:var(--p-border);box-shadow:none;transform:none}.token-link .external-icon{width:13px;height:13px;opacity:.6}.guide-arrow{font-size:22px;color:var(--p-muted);text-align:center}.token-help{display:inline-flex;align-items:center;gap:6px;margin:12px 0 23px;white-space:normal;text-align:left}.token-help .ui-icon{width:15px;height:15px}.review-account-wrap{margin-top:20px;padding-top:4px;border-top:1px solid var(--p-border)}.review-account-wrap .hint{color:var(--p-success);margin:12px 0}#subscription-form>.token-help{float:right;margin:0 0 12px}#subscription-form>label{clear:both}button{transition:background-color var(--motion-base) var(--ease-out),border-color var(--motion-base) var(--ease-out),transform var(--motion-fast) var(--ease-out),box-shadow var(--motion-base) var(--ease-out)}.privacy{max-width:600px;margin-inline:auto}.privacy span{font-size:11px}.public-dialog{color:var(--p-text);background:var(--p-card);border:1px solid var(--p-border);border-radius:22px;padding:28px;width:min(560px,calc(100vw - 32px));max-height:calc(100dvh - 40px);overflow:auto;overscroll-behavior:contain;box-shadow:0 24px 100px #091e1850}.public-dialog::backdrop{background:#06180f70;backdrop-filter:blur(5px)}.dialog-heading{display:flex;align-items:center;justify-content:space-between;gap:18px;margin-bottom:10px}.dialog-heading h2{font-size:23px;letter-spacing:-.6px}.dialog-close{flex:0 0 auto;width:36px;height:36px;font-size:24px;line-height:1;background:var(--p-soft);border:0;color:var(--p-muted)}.dialog-copy{color:var(--p-muted);font-size:13px;margin:0 0 12px}.dialog-back{display:block;margin:18px auto 0;padding:7px 12px}.public-dialog .confirm-label{display:flex;gap:10px;align-items:flex-start;margin:20px 0;font-size:13px;line-height:1.5}.public-dialog .confirm-label input{margin-top:2px}.public-dialog .details{margin-top:10px}.public-dialog .detail{padding:12px 0}.help-steps{list-style:none;counter-reset:help-step;padding:0;margin:24px 0}.help-steps li{position:relative;padding-left:43px;margin-bottom:20px;counter-increment:help-step}.help-steps li::before{content:counter(help-step);position:absolute;left:0;top:2px;border-radius:50%;background:var(--p-soft);color:var(--p-accent);width:28px;height:28px;display:grid;place-items:center;font-size:12px;font-weight:700}.help-steps p{color:var(--p-muted);font-size:13px;margin:8px 0 0}.help-steps .token-link{border:0;padding:0;background:none;box-shadow:none;display:inline-flex}.help-steps li>strong{font-size:14px}.toast{position:fixed;left:50%;bottom:max(24px,env(safe-area-inset-bottom));transform:translateX(-50%);z-index:100;width:max-content;max-width:min(600px,calc(100vw - 32px));display:flex;align-items:center;gap:12px;background:var(--p-card);color:var(--p-text);border:1px solid var(--p-border);border-radius:16px;padding:12px 12px 12px 18px;box-shadow:0 8px 40px #12291d26;font-size:13px;animation:toast-enter var(--motion-base) var(--ease-out)}.toast .icon-button{flex:0 0 auto;width:30px;height:30px;padding:0;border:0;background:var(--p-soft);font-size:20px}.toast-symbol{display:grid;place-items:center;color:var(--p-success);background:var(--p-success-soft);border-radius:50%;height:26px;width:26px;flex:0 0 auto}.toast-symbol::before{content:'✓';font-size:14px}.toast[data-tone=error] .toast-symbol{color:var(--p-warn);background:var(--p-warn-soft)}.toast[data-tone=error] .toast-symbol::before{content:'!';font-weight:700}
@keyframes toast-enter{from{opacity:0;translate:0 12px}to{opacity:1;translate:0 0}}
@media(max-width:600px){.steps{gap:8px;margin-inline:0}.steps li{flex-direction:column;align-items:center;text-align:center;gap:5px;font-size:10px}.steps li b{padding-top:0}.steps li span{width:28px;height:28px}.token-guide{gap:7px;grid-template-columns:minmax(0,1fr) 16px minmax(0,1fr)}.token-link{font-size:11px;gap:6px;padding:12px 9px}.token-link>.ui-icon:first-child{width:18px;height:18px}.token-link .external-icon{display:none}.guide-arrow{font-size:18px}.public-dialog{padding:21px;border-radius:18px}.dialog-heading h2{font-size:20px}.toast{bottom:max(16px,env(safe-area-inset-bottom));gap:9px;font-size:12px}.main{padding-bottom:18px}.help-steps li{padding-left:37px}}
@media(max-width:370px){.token-guide{grid-template-columns:1fr}.guide-arrow{transform:rotate(90deg);line-height:1}.token-link{font-size:12px}.steps li{font-size:9px}.header{gap:8px}.brand{font-size:14px}}
@media(prefers-reduced-motion:reduce){.toast,#account-step,#code-form,#review-account-wrap,.result{animation:none!important}.token-link,button,.steps li span{transition:none!important}.token-link:hover,button:not(:disabled):hover{transform:none}}

/* ── Same geometry as the owner console,kept light ───────────────────────────
   One panel radius,one control radius,one shadow,an 8px rhythm. Entrance,dialog open/close and hover lift are on — same motion system as the console,at the same durations — since every trigger here is a real state change
   (code verified,account confirmed,dialog opened),never a background poll. */
.panel,.tabs,.public-dialog,.toast,.plan-banner,.token-link{border-radius:var(--radius-panel)}
button,input,select,textarea,.tabs a,.detail,.icon-button{border-radius:var(--radius-control)}
.panel{box-shadow:var(--p-shadow);padding:var(--space-3)}
.public-dialog{box-shadow:var(--p-shadow);padding:var(--space-3)}
.primary,.token-link:hover{box-shadow:none}
.tabs{margin-bottom:var(--space-3)}
.steps{margin:0 0 var(--space-3)}
.hint{margin:var(--space-1) 0 var(--space-2)}
.plan-banner{margin-bottom:var(--space-2);background:var(--p-soft)}
.token-help{margin:var(--space-1) 0 var(--space-3)}
.public-dialog::backdrop{backdrop-filter:none;background:#06180f66}
.dialog-close,.toast .icon-button{display:grid;place-items:center;font-size:inherit}
.dialog-close .ui-icon,.toast .icon-button .ui-icon{width:18px;height:18px}

/* Batch code check: a filter row over a plain list. Each state keeps the
   meaning it has elsewhere on the site: ready is positive, revoked is an
   error, a lapsed or used code is neutral. */
.batch-filters{display:flex;flex-wrap:wrap;gap:8px;margin:4px 0 14px}
.batch-filters:empty{display:none}
.batch-chip{width:auto;min-height:0;padding:7px 12px;font-size:12px;font-weight:600}
.batch-chip[aria-pressed=true]{background:var(--p-soft);border-color:var(--p-accent);color:var(--p-accent)}
.batch-state[data-state=reserved],.batch-state[data-state=consumed],.batch-state[data-state=expired]{
  color:var(--p-muted);background:var(--p-soft)}
.batch-state[data-state=revoked],.batch-state[data-state=invalid]{color:var(--p-danger);background:var(--p-warn-soft)}.batch-rows{list-style:none;margin:0;padding:0;display:grid;gap:8px}.batch-row{display:flex;align-items:center;gap:12px;width:100%;text-align:left;padding:11px 14px;border:1px solid var(--p-border);border-radius:12px;background:var(--p-card);transition:background-color var(--motion-base) var(--ease-out),border-color var(--motion-base) var(--ease-out),transform var(--motion-fast) var(--ease-out)}.batch-row:hover{background:var(--p-soft);border-color:var(--p-accent)}.batch-row[aria-current=true]{border-color:var(--p-accent);background:var(--p-soft)}.batch-row .batch-code{font-family:ui-monospace,Consolas,monospace;font-size:13px;font-weight:650;overflow-wrap:anywhere}.batch-row small{margin-left:auto;color:var(--p-muted);font-size:11px}.batch-row .batch-state{margin-left:0}#status-code{min-height:52px;font:13px/1.6 ui-monospace,Consolas,monospace;resize:vertical}.key-code{display:block;margin-top:4px;font-family:ui-monospace,Consolas,monospace;font-size:11px;letter-spacing:.4px;color:var(--p-muted);opacity:.75}.key-code:empty{display:none}
@media(max-width:600px){.batch-rows small{margin-left:0;width:100%}}

/* ── The activation ring ─────────────────────────────────────────────────
   A spinning circle only said that something was happening. The ring says how
   far the run has got: the arc and the number are one value, moved by the
   activation's own phases. Only a finished run closes the circle, and it closes
   on a drawn check rather than on "100%". Colour is the card's own `color`, so
   the accent while it runs and the success green when it is done, with neither
   named here. Geometry is `pathLength="100"`, so the arc is the percentage. */
.status-icon{position:relative;height:44px;width:44px;font-size:20px}
.progress-ring{position:absolute;inset:0;width:100%;height:100%;display:none}
.progress-ring circle{fill:none;stroke-width:3}
.ring-track{stroke:var(--p-border)}
/* Two kinds of motion, saying two different things. The arc below is progress
   and only moves when the run does; this sweep is the heartbeat, and turns for
   as long as work is happening - a phase that takes minutes should not look
   like a page that has died. Faint, so it never reads as progress itself. */
.ring-spin{stroke:currentColor;stroke-linecap:round;stroke-dasharray:14 86;opacity:.34;transform-origin:50% 50%;animation:ring-spin var(--motion-cycle) linear infinite}
@keyframes ring-spin{to{transform:rotate(360deg)}}
.ring-value{stroke:currentColor;stroke-linecap:round;stroke-dasharray:100;transform:rotate(-90deg);transform-origin:50% 50%;transition:stroke-dashoffset var(--motion-fast) linear}
.ring-check{fill:none;stroke:currentColor;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:100;stroke-dashoffset:100}
.status-glyph{position:relative;line-height:1;font-variant-numeric:tabular-nums;letter-spacing:-.3px}
.result[data-state=processing] .status-icon,.result[data-state=succeeded] .status-icon{background:none}
/* Waiting on a person, not on this service. The ring is the same ring -
   work really is happening - but in the caution colour and with no arc and
   no number: there is no stage on this side to measure, and a percentage
   frozen for hours would be a lie told slowly. */
.result[data-state=manual_review] .status-icon{background:none;color:var(--p-warn)}
.result[data-state=manual_review] .progress-ring{display:block}
.result[data-state=manual_review] .ring-value{display:none}
.result[data-state=processing] .progress-ring,.result[data-state=succeeded] .progress-ring{display:block}
.result[data-state=processing] .status-glyph{font-size:13px;font-weight:700}
/* The heartbeat stops when the work does; the check is the only thing moving. */
.result[data-state=succeeded] .ring-spin{display:none}
.result[data-state=succeeded] .status-icon{animation:ring-settle var(--motion-page) var(--ease-out)}
.result[data-state=succeeded] .ring-check{animation:ring-check var(--motion-page) var(--ease-out) var(--motion-fast) forwards}
@keyframes ring-check{to{stroke-dashoffset:0}}
@keyframes ring-settle{from{transform:scale(.9)}to{transform:none}}
@media(max-width:600px){.result-heading .live-badge{margin-left:53px}}
/* Muted, not removed: the check is simply already drawn. */
@media(prefers-reduced-motion:reduce){.result[data-state=succeeded] .ring-check{stroke-dashoffset:0}}


/* ── One control height here too ─────────────────────────────────────────────
   The visitor site keeps its larger touch targets - a phone is the common case
   here, not a desk - but the small controls stop inventing their own numbers:
   the dialog close, the toast dismiss and the batch filter chips all take the
   shared compact height from theme.css, so the row they sit in is level. */
.dialog-close,.toast .icon-button{width:var(--control-h-compact);height:var(--control-h-compact)}
.batch-chip{min-height:var(--control-h-compact)}
.batch-row{min-height:var(--control-h);gap:var(--space-1) var(--space-2);flex-wrap:wrap}
.batch-row .batch-code{flex:1 1 auto;min-width:0}
.batch-row small{flex:0 0 auto}
.batch-filters{gap:var(--space-1);margin:var(--space-1) 0 var(--space-2)}
.batch-rows{gap:var(--space-1)}
.details{margin-top:var(--space-2)}
.section-heading{gap:var(--space-1);flex-wrap:wrap}
.result-heading{gap:var(--space-2)}
.header{padding:var(--space-3) var(--space-4)}
.main{padding-left:var(--space-4);padding-right:var(--space-4)}
footer{padding:var(--space-3) var(--space-4);gap:var(--space-2)}
.preferences{gap:var(--space-1)}
.token-guide{gap:var(--space-1)}
.help-steps{margin:var(--space-3) 0}
.help-steps li{margin-bottom:var(--space-2)}
.dialog-heading{gap:var(--space-2);margin-bottom:var(--space-1)}
@media(max-width:600px){.header{padding:var(--space-2)}.main{padding-left:var(--space-2);padding-right:var(--space-2)}
  footer{padding:var(--space-2)}.panel,.public-dialog{padding:var(--space-2)}}
/* 320px is a real phone, and one long word in a label was enough to push the
   page sideways. Nothing here may set a minimum width the screen cannot meet:
   long strings break, wide boxes scroll inside themselves. */
.batch-row .batch-code,.detail dd,.result-copy,.hint,h1,h2,.key-code{overflow-wrap:anywhere}
.details,.detail,.panel,.public-dialog,.toast,.batch-row{min-width:0}

/* ── Where you are is drawn, not just tinted ─────────────────────────────────
   The same idea as the sidebar rail in the console: the current tab grows a
   rule under it rather than only changing colour. It is a transform on a
   pseudo-element, so it moves no layout, and it is driven by the aria-current
   the router writes - writing the same value again changes no computed style,
   so nothing replays while a status page polls in the background. */
.tabs a{position:relative;overflow:hidden}
.tabs a::after{content:'';position:absolute;left:16%;right:16%;bottom:5px;height:2px;
  border-radius:2px;background:var(--p-accent);transform:scaleX(0);transform-origin:50% 50%;
  opacity:0;transition:transform var(--motion-base) var(--ease-out),opacity var(--motion-fast) var(--ease-out)}
.tabs a[aria-current=page]::after{transform:scaleX(1);opacity:1}

/* A step that has just been completed settles into place. It is keyed on the
   class renderSteps() writes, and that function assigns the same string on
   every render, so the animation starts when the step really changes and not
   once per poll. Scale only: the marker is fully readable at every frame. */
@keyframes step-settle{from{transform:scale(.86)}to{transform:none}}
.steps li.done span{animation:step-settle var(--motion-base) var(--ease-out)}

@media(prefers-reduced-motion:reduce){
  .tabs a::after{transition:none!important}
  .steps li.done span{animation:none!important}
}

/* ── One column, three bands ─────────────────────────────────────────────────
   The logo, the activation card and the footer used to be centred on 1040,
   840 and 976px, so no two of their left edges agreed at any width above the
   reading measure - the header sat 100px outside the card it belongs to. One
   measure now, the reading width the card was already built for, and the
   horizontal padding is the same token in all three (--space-4, --space-2
   below 600px), so the edges line up at every width instead of at none. */
:root{--p-measure:840px}

/* ── The mark says whether the platform is running ───────────────────────────
   The mark is on screen for the whole visit, so it breathes slowly and by very
   little: a state you glance at, never a thing that asks to be watched. The
   two states differ by colour, and the colour is where the animation ends -
   calm and peak are custom properties the keyframes read, so switching state
   re-resolves them under a running animation instead of restarting it, and
   nothing jumps. Under reduced motion the animation is off site-wide and the
   base colour still carries the state; the info button carries it as well. */
.brand-group{display:flex;align-items:center;gap:var(--space-1);min-width:0}
.brand{gap:var(--space-1);min-width:0}
.header{--mark-calm:color-mix(in srgb,var(--p-success) 74%,var(--p-muted));--mark-peak:var(--p-success);--mark-breath:6.5s}
.header[data-platform=maintenance]{--mark-calm:var(--p-warn);--mark-peak:var(--p-danger)}
/* The state rides the wordmark, not the mark. The mark is 24px of solid shape
   and a slow colour change across it reads as a glitch in the logo; the word
   is the thing a visitor is already looking at, and text carries a tint at
   this weight without looking broken. The mark stays the brand colour. */
.brandmark{width:24px;height:24px;flex:0 0 auto;color:var(--p-accent)}
.brandword{color:var(--mark-calm);animation:brand-breathe var(--mark-breath) var(--ease-in-out) infinite}
/* Colour only, never opacity. Fading the word to .78 measured 3.16:1 against
   the page ground - the wordmark is 14px at weight 750, which is not large
   text, so it owes 4.5:1 for every frame of a loop that never stops. Both
   colours clear it on their own (4.9 and 5.4), so the breath is carried by the
   hue and the word stays readable at every point in the cycle. */
@keyframes brand-breathe{0%,100%{color:var(--mark-calm)}50%{color:var(--mark-peak)}}
/* Present only while there is something to read, and it fades both ways: the
   discrete display transition is what keeps the exit from being a snap. */
.platform-info{display:none;padding:0;place-items:center;color:var(--p-warn);background:var(--p-warn-soft);border-color:transparent;opacity:0;transform:scale(.92);transition:opacity var(--motion-base) var(--ease-out),transform var(--motion-base) var(--ease-out),display var(--motion-base) allow-discrete}
.header[data-platform=maintenance] .platform-info{display:grid;opacity:1;transform:none}
@starting-style{.header[data-platform=maintenance] .platform-info{opacity:0;transform:scale(.92)}}
.platform-info .ui-icon{width:19px;height:19px}
#maintenance-notice{white-space:pre-wrap;overflow-wrap:anywhere}
@media(max-width:600px){.brandmark{width:20px;height:20px}}

/* ── Stopping before it costs anything ───────────────────────────────────────
   Whether an activation can still be stopped is a money boundary, so the
   server answers it and this only draws the answer. When the answer is no the
   control stays where it was, disabled, with the reason beside it: hiding it
   would read as "there is no such thing", which is the opposite of true. The
   window note is on the card at all times, not only once it is too late. */
.stop-activation{margin-top:var(--space-2);padding-top:var(--space-2);border-top:1px solid var(--p-border)}
.stop-button{width:auto;min-height:var(--control-h);display:inline-flex;align-items:center;justify-content:flex-start;gap:var(--space-1);padding:10px 16px}
.stop-button .ui-icon{width:18px;height:18px}
.stop-reason,.stop-window{margin:var(--space-1) 0 0;font-size:12px}
.stop-reason{color:var(--p-warn)}
.cancel-released{color:var(--p-success);margin:var(--space-1) 0 0}
#cancel-details{grid-template-columns:minmax(0,1fr)}
#cancel-details .detail{padding-right:0}
/* The code input asks for the code; a line under it repeating that the code
   starts with BG- said it twice. The button keeps the gap the line used to. */
#code-form .primary{margin-top:var(--space-2)}
/* It slides in, so it slides out. */
.toast{transition:opacity var(--motion-base) var(--ease-out),translate var(--motion-base) var(--ease-out)}
.toast[data-leaving]{opacity:0;translate:0 12px}
