diff --git a/internal/cloudcp/portal/dist/build_manifest.json b/internal/cloudcp/portal/dist/build_manifest.json index 33326721cd..5756dd9287 100644 --- a/internal/cloudcp/portal/dist/build_manifest.json +++ b/internal/cloudcp/portal/dist/build_manifest.json @@ -1,5 +1,5 @@ { - "source_hash": "f7b726f8e8d6c01630420d83fad1e59f7947f386a570d1715f0165f958c39410", + "source_hash": "3ee5dcea0783b4085b4a7feb3fd0dcee628b4280042752af29256a685db8a466", "build_inputs": [ "package.json", "tsconfig.json", diff --git a/internal/cloudcp/portal/dist/portal_app.css b/internal/cloudcp/portal/dist/portal_app.css index 6c24d87dd6..d7c997966e 100644 --- a/internal/cloudcp/portal/dist/portal_app.css +++ b/internal/cloudcp/portal/dist/portal_app.css @@ -232,26 +232,18 @@ header .logout-btn:hover, line-height: 1.05; letter-spacing: -0.04em; } -.portal-frame { +.portal-shell-bar { display: grid; - grid-template-columns: minmax(220px, 250px) minmax(0, 1fr); - gap: 22px; - align-items: start; -} -.portal-rail { - position: sticky; - top: 88px; - display: flex; - flex-direction: column; + grid-template-columns: minmax(0, 1fr) auto; gap: 16px; + align-items: stretch; } .portal-section-nav { - display: flex; - flex-direction: column; + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; } .portal-section-link, -.portal-rail-panel, .intro-card, .service-panel, .account-surface, @@ -287,30 +279,41 @@ header .logout-btn:hover, line-height: 1.5; color: var(--ink-soft); } -.portal-rail-panel { - border-radius: var(--radius-md); - padding: 20px; -} -.portal-rail-panel h3 { - margin: 8px 0 10px; - font-size: 23px; - line-height: 1.05; - letter-spacing: -0.04em; -} -.portal-rail-panel p { - margin: 0; - color: var(--ink-soft); - line-height: 1.6; -} .portal-support-link, .support-link, .service-panel .helper-text a { color: var(--accent-strong); font-weight: 600; } -.portal-support-link { - display: inline-block; - margin-top: 14px; +.portal-support-strip { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + min-width: 340px; + padding: 16px 18px; + border: 1px solid var(--line); + border-radius: var(--radius-md); + background: rgba(255, 255, 255, 0.98); + box-shadow: var(--shadow-sm); +} +.portal-support-copy { + display: flex; + flex-direction: column; + gap: 4px; +} +.portal-support-label { + font-size: 11px; + font-weight: 800; + letter-spacing: 0.14em; + text-transform: uppercase; + color: var(--ink-muted); +} +.portal-support-text { + max-width: 280px; + font-size: 13px; + line-height: 1.5; + color: var(--ink-soft); } .portal-stage { display: flex; @@ -896,17 +899,15 @@ header .logout-btn:hover, background: #6e1414; } @media (max-width: 1180px) { - .portal-frame, .account-management-grid, .team-management-grid { grid-template-columns: 1fr; } - .portal-rail { - position: static; + .portal-shell-bar { + grid-template-columns: 1fr; } - .portal-section-nav { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); + .portal-support-strip { + min-width: 0; } .account-overview-rail { grid-template-columns: 1fr; diff --git a/internal/cloudcp/portal/dist/portal_app.js b/internal/cloudcp/portal/dist/portal_app.js index c7b243c08a..c2f7dca77b 100644 --- a/internal/cloudcp/portal/dist/portal_app.js +++ b/internal/cloudcp/portal/dist/portal_app.js @@ -1672,7 +1672,7 @@ var hosted = hasHostedAccounts(accounts); var serviceHeading = hosted ? "Self-hosted licenses and billing" : "Account services"; var serviceNote = hosted ? "Hosted operations live above. Use these commercial tools for self-hosted licenses, billing, refunds, and privacy actions." : "Use these account tools for self-hosted licenses, billing, refunds, and privacy actions."; - return '
' + renderOverviewBand(accounts) + '

" + (hosted ? "Run hosted accounts from one place" : "No hosted workspaces are attached yet") + "

" + (hosted ? "Use this area for workspace access, fleet operations, hosted billing, and team management." : "This account does not currently have hosted workspace access. If that is unexpected, contact support while using the commercial tools below.") + '

' + renderAccountsHTML(context) + '

' + serviceHeading + '

' + serviceNote + '

Data and privacy

Request export or deletion of the commercial data tied to an email address. Payment data held directly by Stripe still requires support handling.

Payment-card data stays with Stripe. For Stripe deletion support, contact ' + escapeHTML(context.bootstrap.support_email || "") + ".
"; + return '
' + renderOverviewBand(accounts) + '
' + renderShellNavigation(accounts, context.bootstrap.support_email || "") + '
SupportHosted operations and commercial account tools now share one account surface.
' + escapeHTML(context.bootstrap.support_email || "") + '

" + (hosted ? "Run hosted accounts from one place" : "No hosted workspaces are attached yet") + "

" + (hosted ? "Use this area for workspace access, fleet operations, hosted billing, and team management." : "This account does not currently have hosted workspace access. If that is unexpected, contact support while using the commercial tools below.") + '

' + renderAccountsHTML(context) + '

' + serviceHeading + '

' + serviceNote + '

Data and privacy

Request export or deletion of the commercial data tied to an email address. Payment data held directly by Stripe still requires support handling.

Payment-card data stays with Stripe. For Stripe deletion support, contact ' + escapeHTML(context.bootstrap.support_email || "") + ".
"; } function renderSignedOutPortalHTML(context) { var statusHTML = ""; diff --git a/internal/cloudcp/portal/frontend/src/shell_view.ts b/internal/cloudcp/portal/frontend/src/shell_view.ts index 80801bd743..ff00f3ccaf 100644 --- a/internal/cloudcp/portal/frontend/src/shell_view.ts +++ b/internal/cloudcp/portal/frontend/src/shell_view.ts @@ -497,74 +497,71 @@ export function renderAuthenticatedPortalHTML(context: ShellViewContext): string return ( '
' + renderOverviewBand(accounts) + - '
' + - '' + - '
' + - '
' + - '
' + - '' + - '

' + (hosted ? 'Run hosted accounts from one place' : 'No hosted workspaces are attached yet') + '

' + - '

' + (hosted - ? 'Use this area for workspace access, fleet operations, hosted billing, and team management.' - : 'This account does not currently have hosted workspace access. If that is unexpected, contact support while using the commercial tools below.') + '

' + - '
' + - '
' + renderAccountsHTML(context) + '
' + - '
' + - '
' + - '
' + - '
' + - '' + - '

' + serviceHeading + '

' + - '
' + - '
' + serviceNote + '
' + - '
' + - '
' + - '' + - '' + - '' + - '' + - '
' + - '
' + - '
' + - '
' + - '
' + - '

Data and privacy

' + - '

Request export or deletion of the commercial data tied to an email address. Payment data held directly by Stripe still requires support handling.

' + - '
' + - '
' + - '
Payment-card data stays with Stripe. For Stripe deletion support, contact ' + - escapeHTML(context.bootstrap.support_email || '') + - '.
' + - '
' + - '
' + + '' + escapeHTML(context.bootstrap.support_email || '') + '' + '
' + '
' + + '
' + + '
' + + '' + + '

' + (hosted ? 'Run hosted accounts from one place' : 'No hosted workspaces are attached yet') + '

' + + '

' + (hosted + ? 'Use this area for workspace access, fleet operations, hosted billing, and team management.' + : 'This account does not currently have hosted workspace access. If that is unexpected, contact support while using the commercial tools below.') + '

' + + '
' + + '
' + renderAccountsHTML(context) + '
' + + '
' + + '
' + + '
' + + '
' + + '' + + '

' + serviceHeading + '

' + + '
' + + '
' + serviceNote + '
' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '
' + + '
' + + '
' + + '

Data and privacy

' + + '

Request export or deletion of the commercial data tied to an email address. Payment data held directly by Stripe still requires support handling.

' + + '
' + + '
' + + '
Payment-card data stays with Stripe. For Stripe deletion support, contact ' + + escapeHTML(context.bootstrap.support_email || '') + + '.
' + + '
' + + '
' + '
' ); } diff --git a/internal/cloudcp/portal/frontend/src/styles.css b/internal/cloudcp/portal/frontend/src/styles.css index cb60557838..20f33336cd 100644 --- a/internal/cloudcp/portal/frontend/src/styles.css +++ b/internal/cloudcp/portal/frontend/src/styles.css @@ -243,29 +243,20 @@ header .logout-btn:hover, letter-spacing: -0.04em; } -.portal-frame { +.portal-shell-bar { display: grid; - grid-template-columns: minmax(220px, 250px) minmax(0, 1fr); - gap: 22px; - align-items: start; -} - -.portal-rail { - position: sticky; - top: 88px; - display: flex; - flex-direction: column; + grid-template-columns: minmax(0, 1fr) auto; gap: 16px; + align-items: stretch; } .portal-section-nav { - display: flex; - flex-direction: column; + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; } .portal-section-link, -.portal-rail-panel, .intro-card, .service-panel, .account-surface, @@ -303,24 +294,6 @@ header .logout-btn:hover, color: var(--ink-soft); } -.portal-rail-panel { - border-radius: var(--radius-md); - padding: 20px; -} - -.portal-rail-panel h3 { - margin: 8px 0 10px; - font-size: 23px; - line-height: 1.05; - letter-spacing: -0.04em; -} - -.portal-rail-panel p { - margin: 0; - color: var(--ink-soft); - line-height: 1.6; -} - .portal-support-link, .support-link, .service-panel .helper-text a { @@ -328,9 +301,38 @@ header .logout-btn:hover, font-weight: 600; } -.portal-support-link { - display: inline-block; - margin-top: 14px; +.portal-support-strip { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + min-width: 340px; + padding: 16px 18px; + border: 1px solid var(--line); + border-radius: var(--radius-md); + background: rgba(255, 255, 255, 0.98); + box-shadow: var(--shadow-sm); +} + +.portal-support-copy { + display: flex; + flex-direction: column; + gap: 4px; +} + +.portal-support-label { + font-size: 11px; + font-weight: 800; + letter-spacing: 0.14em; + text-transform: uppercase; + color: var(--ink-muted); +} + +.portal-support-text { + max-width: 280px; + font-size: 13px; + line-height: 1.5; + color: var(--ink-soft); } .portal-stage { @@ -1002,19 +1004,17 @@ header .logout-btn:hover, .toast.error { background: #6e1414; } @media (max-width: 1180px) { - .portal-frame, .account-management-grid, .team-management-grid { grid-template-columns: 1fr; } - .portal-rail { - position: static; + .portal-shell-bar { + grid-template-columns: 1fr; } - .portal-section-nav { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); + .portal-support-strip { + min-width: 0; } .account-overview-rail {