/* AlpsCraft ERP — Customer Portal skin ("Warm Editorial + Alpine").

   PURPOSE
   Visual layer for the client portal (/portal/**) only. Loaded by
   templates/portal/layout/portal.html and the six standalone portal auth
   pages, AFTER components.css. Every rule is scoped under `body.portal-app`
   so it overrides the shared component blocks by both specificity and load
   order, and is completely inert on admin pages (which never carry the class).

   CONTRACT
   - Reuses the existing palette + tokens verbatim (tokens.css). No new colors,
     no new fonts — only a richer application of Fraunces (display), JetBrains
     Mono (data) and the moss/clay accents already in the brand.
   - Colors via tokens / `rgb(var(--color-*-rgb) / α)` channel vars only, so the
     dark theme (portal users may opt in via theme-init.js) keeps working.
   - CSS-only. No new JS. All motion sits behind prefers-reduced-motion guards.
   - Decorative primitives (.hero-aura, .ridge-accent, .lift) are adapted from
     public-landing.css; that file is contractually landing-page-only, so the
     primitives are re-declared here under portal scope rather than shared.

   SECTIONS
     1. Decorative primitives (aura, ridge, lift, contour motif)
     2. Typography — Fraunces headings + mono data
     3. Motion — extra stagger steps + reduced-motion
   Page-specific sections (topbar/footer, dashboard, product detail, support,
   announcements, auth, errors) follow in their own clearly-marked blocks. */


/* ══════════════════════════════════════════════════════════════════
   1 · DECORATIVE PRIMITIVES
   ══════════════════════════════════════════════════════════════════ */

/* Layered hero backdrop — soft moss/clay "aurora" mesh over warm cream plus a
   fine desaturated grain. Drop as an absolutely-positioned, aria-hidden child of
   a position:relative container; it sits behind content and ignores pointers.
   Adapted from public-landing.css .hero-aura (different inset/opacity for the
   tighter portal hero card). */
.portal-app .hero-aura {
    position: absolute;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    pointer-events: none;
    border-radius: inherit;
    -webkit-mask-image: linear-gradient(to bottom, #000 60%, transparent 100%);
            mask-image: linear-gradient(to bottom, #000 60%, transparent 100%);
}
.portal-app .hero-aura::before {
    content: "";
    position: absolute;
    inset: -30% -10% 0 -10%;
    background:
        radial-gradient(44% 60% at 14% 6%,  rgb(var(--color-accent-rgb) / 0.22), transparent 60%),
        radial-gradient(38% 52% at 92% -4%, rgb(var(--color-cta-rgb)    / 0.18), transparent 62%),
        radial-gradient(72% 68% at 52% -12%, rgb(var(--color-accent-rgb) / 0.08), transparent 74%);
    filter: saturate(1.05);
}
/* Grain: tiny tiled SVG noise (data: URI — allowed by portal CSP img-src 'self' data:). */
.portal-app .hero-aura::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    opacity: 0.28;
    mix-blend-mode: multiply;
}
/* On dark surfaces the multiply grain muddies — lighten + screen instead. */
[data-theme="dark"] .portal-app .hero-aura::after {
    opacity: 0.10;
    mix-blend-mode: screen;
}

/* Ridge accent — the unifying motif (echoed as a solid bar in the email card and
   PDF header). A refined moss→clay→moss hairline nodding to the logo ridge. */
.portal-app .ridge-accent {
    height: 3px;
    width: 100%;
    border: 0;
    margin: 0;
    border-radius: var(--radius-pill);
    background: linear-gradient(90deg,
        transparent 0%,
        rgb(var(--color-accent-rgb) / 0.65) 14%,
        var(--color-accent) 38%,
        var(--color-cta) 50%,
        var(--color-accent) 62%,
        rgb(var(--color-accent-rgb) / 0.65) 86%,
        transparent 100%);
}
/* Short left-anchored variant for section headers. */
.portal-app .ridge-accent--short {
    width: 2.5rem;
    height: 2px;
    background: linear-gradient(90deg, var(--color-accent), var(--color-cta));
}

/* Hover lift — cards/tiles. Reduced-motion users get the shadow only (block below). */
.portal-app .lift {
    transition: transform var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out),
                border-color var(--dur) var(--ease-out);
}
.portal-app .lift:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-overlay);
}

/* Alpine contour ridgelines (used by empty states + error pages below) are drawn
   as CSS masks filled with var(--color-accent) so they recolor with the theme —
   see §10. */


/* ══════════════════════════════════════════════════════════════════
   2 · TYPOGRAPHY — Fraunces display headings + mono data
   The portal's strongest brand lever. Section titles jump from 16px Inter to
   editorial-scale Fraunces; data (versions, dates, ids, checksums) goes mono.
   ══════════════════════════════════════════════════════════════════ */

/* Hero greeting — large optical-size Fraunces. */
.portal-app .hero__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(2.25rem, 1.4rem + 3.4vw, 3.25rem);
    font-variation-settings: 'opsz' 40;
    line-height: var(--lh-tight);
    letter-spacing: var(--ls-tighter);
}

/* Section titles — "Ihre Produkte", "Releases", "Service coverage"… */
.portal-app .section-title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(1.375rem, 1.05rem + 1.25vw, 1.625rem);
    font-variation-settings: 'opsz' 30;
    letter-spacing: var(--ls-tight);
    line-height: var(--lh-snug);
}

/* Page H1 (product detail) + empty-state + auth card title. */
.portal-app .page-header__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(1.875rem, 1.3rem + 2.2vw, 2.5rem);
    font-variation-settings: 'opsz' 36;
    letter-spacing: var(--ls-tighter);
    line-height: var(--lh-tight);
}
.portal-app .empty-state__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-2xl);
    font-variation-settings: 'opsz' 24;
    letter-spacing: var(--ls-tight);
}
.portal-app .auth-card h1 {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-3xl);
    font-variation-settings: 'opsz' 30;
    letter-spacing: var(--ls-tight);
}

/* Eyebrows — uppercase mono micro-labels that structure each section. */
.portal-app .eyebrow {
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: var(--fs-2xs);
    letter-spacing: var(--ls-eyebrow);
    text-transform: uppercase;
    color: var(--color-accent);
}

/* Section header gains breathing room + an optional eyebrow row. */
.portal-app .section-header { margin-bottom: 1.25rem; }
.portal-app .section-sub {
    font-size: var(--fs-sm);
    color: var(--color-fg-secondary);
    margin-top: 0.375rem;
    max-width: var(--prose-max);
}


/* ══════════════════════════════════════════════════════════════════
   3 · MOTION — extra stagger steps + reduced-motion guard
   Reuses the shared `fade-up` keyframes (components.css); adds later delays.
   ══════════════════════════════════════════════════════════════════ */
.portal-app .fade-in-5 { animation: fade-up var(--dur-slow) var(--ease-out) both; animation-delay: 200ms; }
.portal-app .fade-in-6 { animation: fade-up var(--dur-slow) var(--ease-out) both; animation-delay: 240ms; }

@media (prefers-reduced-motion: reduce) {
    .portal-app .lift { transition: box-shadow var(--dur) var(--ease-out); }
    .portal-app .lift:hover { transform: none; }
    .portal-app [class*="fade-in"] { animation: none !important; }
}


/* ══════════════════════════════════════════════════════════════════
   4 · LAYOUT CHROME — topbar active state + footer
   ══════════════════════════════════════════════════════════════════ */

/* Active nav link: persistent moss underline + accent text (the shared
   ::after underline only shows on hover; aria-current pins it on). */
.portal-app .topbar__nav-link[aria-current="page"] {
    color: var(--color-accent);
    font-weight: 550;
}
.portal-app .topbar__nav-link[aria-current="page"]::after {
    transform: scaleX(1);
    height: 2px;
}

/* Mobile slide-down panel: the active row gets a soft moss wash + left rail. */
@media (max-width: 899px) {
    .portal-app .topbar__cluster .topbar__nav-link[aria-current="page"] {
        background: var(--color-accent-bg);
        box-shadow: inset 2px 0 0 var(--color-accent);
    }
    .portal-app .topbar__cluster .topbar__nav-link[aria-current="page"]::after { display: none; }
}

/* Topbar quick theme toggle — a single icon button that flips light↔dark (the full
   System/Light/Dark control lives on the preferences page). The moon shows in light
   mode (→ go dark), the sun in dark mode (→ go light); the swap is driven by
   [data-theme] on <html>, so it tracks the theme with no JS and no flash. */
.portal-app .topbar__theme-toggle { padding-inline: 0.5rem; }
.portal-app .topbar__theme-icon { display: block; }
.portal-app .topbar__theme-icon--sun { display: none; }
:root[data-theme="dark"] .portal-app .topbar__theme-icon--moon { display: none; }
:root[data-theme="dark"] .portal-app .topbar__theme-icon--sun { display: block; }

/* Footer — ridge accent over a two-part brand/meta row. */
.portal-app .portal-footer {
    text-align: left;
    padding: 0;
    margin-top: 3rem;
    background: transparent;
    border-top: 0;
}
.portal-app .portal-footer__ridge { opacity: 0.7; }
.portal-app .portal-footer__inner {
    max-width: var(--layout-max);
    margin-inline: auto;
    width: 100%;
    padding: 1.25rem var(--layout-pad) 1.5rem;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem 1.5rem;
}
.portal-app .portal-footer__brand {
    display: inline-flex;
    align-items: baseline;
    gap: 0.625rem;
    flex-wrap: wrap;
}
.portal-app .portal-footer__name {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-md);
    font-variation-settings: 'opsz' 18;
    letter-spacing: var(--ls-tight);
    color: var(--color-fg-secondary);
}
.portal-app .portal-footer__tagline {
    font-size: var(--fs-xs);
    color: var(--color-fg-muted);
}
.portal-app .portal-footer__meta {
    display: inline-flex;
    align-items: baseline;
    gap: 0.5rem;
    font-size: var(--fs-xs);
    color: var(--color-fg-muted);
    font-family: var(--font-mono);
    letter-spacing: 0;
}
.portal-app .portal-footer__sep { color: var(--color-fg-muted); opacity: 0.6; }


/* ══════════════════════════════════════════════════════════════════
   5 · DASHBOARD — hero, stat strip, product cards, downloads
   ══════════════════════════════════════════════════════════════════ */

/* Hero: roomier card, aura backdrop owns all decoration (kill the shared grid). */
.portal-app .portal-hero {
    padding: clamp(2rem, 1.4rem + 2.6vw, 3.25rem) clamp(1.5rem, 1rem + 2vw, 2.75rem);
    border-radius: var(--radius-xl);
    background: linear-gradient(180deg, var(--color-bg-elevated), var(--color-bg-base));
    box-shadow: var(--shadow-card);
}
.portal-app .portal-hero::before { display: none; }
.portal-app .portal-hero .hero__inner { max-width: 60ch; }
.portal-app .portal-hero__eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
    color: var(--color-accent);
}
.portal-app .portal-hero__eyebrow time { color: var(--color-fg-tertiary); }
.portal-app .portal-hero__dot { color: var(--color-cta); opacity: 0.7; }
.portal-app .portal-hero__ridge { margin-top: 1.5rem; }
.portal-app .hero__subtitle { margin-top: 0.75rem; }

/* Stat strip — a magazine-masthead row of figures. Hairline-divided tiles that
   collapse to a 2×2 grid on narrow screens. */
.portal-app .portal-stats {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1px;
    margin-bottom: 2rem;
    background: var(--color-border-subtle);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-lg);
    overflow: hidden;
}
@media (max-width: 640px) {
    .portal-app .portal-stats { grid-template-columns: repeat(2, 1fr); }
}
.portal-app .portal-stat {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 1.125rem 1.25rem;
    background: var(--color-bg-elevated);
}
.portal-app .portal-stat__value {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-4xl);
    font-variation-settings: 'opsz' 32;
    line-height: 1;
    color: var(--color-fg-primary);
    font-variant-numeric: tabular-nums;
}
.portal-app .portal-stat__label {
    font-family: var(--font-mono);
    font-size: var(--fs-2xs);
    letter-spacing: var(--ls-wide);
    text-transform: uppercase;
    color: var(--color-fg-tertiary);
}

/* Product cards — editorial hierarchy + a gentle moss top-rail on hover. */
.portal-app .product-card {
    gap: 0.5rem;
    transition: transform var(--dur) var(--ease-out),
                border-color var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out),
                background var(--dur) var(--ease-out);
}
/* Override the dark-tuned hover shadow with the theme-aware overlay token. */
.portal-app .product-card:hover {
    transform: translateY(-3px);
    border-color: rgb(var(--color-accent-rgb) / 0.3);
    box-shadow: var(--shadow-overlay);
    background: var(--color-bg-elevated);
}
.portal-app .product-card__head { min-height: 1.25rem; }
.portal-app .product-card__eyebrow { color: var(--color-accent); }
.portal-app .product-card__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-xl);
    font-variation-settings: 'opsz' 22;
    letter-spacing: var(--ls-tight);
    line-height: var(--lh-snug);
}
.portal-app .product-card__meta code {
    font-family: var(--font-mono);
    color: var(--color-fg-tertiary);
}

/* Expired tile — desaturated, no inline opacity hack. */
.portal-app .product-card[data-state="expired"] {
    background: var(--color-bg-inset);
    opacity: 0.85;
}
.portal-app .product-card[data-state="expired"]:hover { transform: none; box-shadow: var(--shadow-sm); }
.portal-app .product-card[data-state="expired"] .product-card__title { color: var(--color-fg-secondary); }

/* Neutral pill (previously an undefined modifier patched with inline hex). */
.portal-app .pill--muted {
    background: var(--color-neutral-bg);
    color: var(--color-neutral-fg);
    border-color: var(--color-border-subtle);
}

/* Dashboard message preview cards. */
.portal-app .portal-message-list { display: flex; flex-direction: column; }
.portal-app .portal-message-card { margin-bottom: 0.75rem; }
.portal-app .portal-message-card:last-child { margin-bottom: 0; }

/* Downloads table — mono data already on version/date; tighten the dim cells. */
.portal-app .table .mono { color: var(--color-fg-secondary); }
.portal-app .table tbody td .text-tertiary { color: var(--color-fg-tertiary); }


/* ══════════════════════════════════════════════════════════════════
   6 · PRODUCT DETAIL — release timeline + coverage
   ══════════════════════════════════════════════════════════════════ */

/* Vertical timeline: a continuous moss rail in the left gutter, a node per
   release, the existing .release-card sitting to its right (card markup intact
   so the admin copy of .release-card is unaffected). */
.portal-app .release-timeline {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.875rem;
}
.portal-app .release-timeline::before {
    content: "";
    position: absolute;
    left: 6px;
    top: 0.75rem;
    bottom: 0.75rem;
    width: 2px;
    border-radius: 2px;
    background: linear-gradient(180deg,
        var(--color-accent) 0%,
        rgb(var(--color-accent-rgb) / 0.18) 100%);
}
.portal-app .release-timeline__item {
    position: relative;
    padding-left: 2rem;
}
.portal-app .release-timeline__node {
    position: absolute;
    left: 0;
    top: 1.625rem;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--color-bg-elevated);
    border: 2px solid var(--color-accent);
    box-shadow: 0 0 0 4px var(--color-bg-base);
    z-index: 1;
}
/* Newest release gets a filled clay node to read as "latest". */
.portal-app .release-timeline__node.is-latest {
    background: var(--color-cta);
    border-color: var(--color-cta);
}
@media (max-width: 540px) {
    .portal-app .release-timeline__item { padding-left: 1.5rem; }
    .portal-app .release-timeline::before { display: none; }
    .portal-app .release-timeline__node { position: static; display: none; }
}

/* Version row + "Latest" pill. */
.portal-app .release-card__version-row {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
}
.portal-app .release-badge-latest {
    display: inline-flex;
    align-items: center;
    padding: 0.125rem 0.5rem;
    border-radius: var(--radius-pill);
    background: rgb(var(--color-cta-rgb) / 0.14);
    color: var(--color-cta);
    border: 1px solid rgb(var(--color-cta-rgb) / 0.30);
    font-family: var(--font-mono);
    font-size: var(--fs-2xs);
    font-weight: 500;
    letter-spacing: var(--ls-wide);
    text-transform: uppercase;
}

/* Markdown-rendered release notes: drop the plain-text pre-wrap so prose owns
   spacing for paragraphs/lists/code. */
.portal-app .release-card__notes.prose { white-space: normal; }
.portal-app .release-card__notes.prose > :first-child { margin-top: 0; }
.portal-app .release-card__notes.prose > :last-child { margin-bottom: 0; }

/* Coverage hero date in Fraunces (the brief calls it out explicitly). */
.portal-app .entitlement-card__date {
    font-family: var(--font-display);
    font-variation-settings: 'opsz' 30;
    font-weight: 600;
    letter-spacing: var(--ls-tight);
}
.portal-app .entitlement-card__eyebrow {
    font-family: var(--font-mono);
    text-transform: uppercase;
    letter-spacing: var(--ls-eyebrow);
}


/* ══════════════════════════════════════════════════════════════════
   7 · SUPPORT — ticket cards + pipeline (mostly inherited from §5 cards)
   The shared .support-pipeline / .comment components are already token-based;
   only portal-scoped touches here so admin support is untouched.
   ══════════════════════════════════════════════════════════════════ */

/* Ticket card date → mono, matching the "data is mono" rhythm. */
.portal-app .product-card__meta--small {
    font-family: var(--font-mono);
    color: var(--color-fg-tertiary);
    letter-spacing: 0;
}

/* Pipeline reads as a distinct band on its own inset rail. */
.portal-app .support-pipeline {
    background: var(--color-bg-inset);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-lg);
    padding: 0.75rem 1rem;
}

/* Comment author name in display serif for a touch of editorial warmth. */
.portal-app .comment__author {
    font-family: var(--font-display);
    font-variation-settings: 'opsz' 16;
    font-weight: 600;
    letter-spacing: var(--ls-tight);
}


/* ══════════════════════════════════════════════════════════════════
   8 · ANNOUNCEMENTS + PREFERENCES
   ══════════════════════════════════════════════════════════════════ */

.portal-app .portal-announcement-list { display: flex; flex-direction: column; gap: 0.75rem; }
.portal-app .portal-announcement-card { position: relative; }
/* Unread gets a clay rail + slightly stronger surface. */
.portal-app .portal-announcement-card.is-unread {
    border-color: rgb(var(--color-cta-rgb) / 0.28);
    box-shadow: inset 3px 0 0 var(--color-cta);
}
.portal-app .portal-announcement-card__date { margin-top: 0.5rem; }
.portal-app .portal-announcement-card__dismiss { margin-top: 0.75rem; }

/* Message body: plain text with preserved line breaks, comfortable measure. */
.portal-app .portal-message-body {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font-size: var(--fs-md);
    line-height: var(--lh-body);
    color: var(--color-fg-secondary);
    max-width: var(--prose-max);
}

/* Attachment rows. */
.portal-app .portal-attachment-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.portal-app .portal-attachment-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.625rem 0.875rem;
    background: var(--color-bg-elevated);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
}
.portal-app .portal-attachment-row__icon { color: var(--color-accent); display: inline-flex; flex-shrink: 0; }
.portal-app .portal-attachment-row__name { font-weight: 500; color: var(--color-fg-primary); min-width: 0; overflow-wrap: anywhere; }
.portal-app .portal-attachment-row__size { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--color-fg-muted); }
.portal-app .portal-attachment-row__actions { margin-left: auto; display: inline-flex; gap: 0.375rem; flex-shrink: 0; }

/* Preferences title in Fraunces (its .settings-head__title isn't caught by the
   shared heading overrides above). */
.portal-app .settings-head__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(1.875rem, 1.3rem + 2.2vw, 2.5rem);
    font-variation-settings: 'opsz' 36;
    letter-spacing: var(--ls-tighter);
    line-height: var(--lh-tight);
}

/* Appearance — System / Light / Dark segmented control (instant client-side toggle).
   Buttons are wired by theme-toggle.js; the active option carries aria-pressed="true".
   All token-based, so it recolors automatically with the active theme. */
.portal-app .theme-seg {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.625rem;
}
.portal-app .theme-seg__opt {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 1.125rem 0.75rem;
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
    background: var(--color-bg-base);
    color: var(--color-fg-secondary);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 500;
    cursor: pointer;
    transition: transform var(--dur) var(--ease-out),
                border-color var(--dur) var(--ease-out),
                background var(--dur) var(--ease-out),
                color var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out);
}
.portal-app .theme-seg__opt:hover { border-color: var(--color-border-strong); }
.portal-app .theme-seg__opt:active { transform: translateY(0.5px); }
.portal-app .theme-seg__opt:focus-visible {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px rgb(var(--color-accent-rgb) / 0.25);
}
.portal-app .theme-seg__icon {
    width: 22px;
    height: 22px;
    color: var(--color-fg-tertiary);
    transition: color var(--dur) var(--ease-out);
}
.portal-app .theme-seg__opt[aria-pressed="true"] {
    border-color: rgb(var(--color-accent-rgb) / 0.5);
    background: var(--color-accent-bg);
    color: var(--color-accent);
}
.portal-app .theme-seg__opt[aria-pressed="true"] .theme-seg__icon { color: var(--color-accent); }
.portal-app .theme-seg__hint {
    margin: 0.875rem 0 0;
    font-size: var(--fs-xs);
    color: var(--color-fg-muted);
}
@media (prefers-reduced-motion: reduce) {
    .portal-app .theme-seg__opt { transition: none; }
    .portal-app .theme-seg__opt:active { transform: none; }
}


/* ══════════════════════════════════════════════════════════════════
   9 · AUTH PAGES — warmer aura + a ridge-crowned card
   The shared .auth-shell already carries a moss/clay radial backdrop; here we
   warm it slightly and crown the card with the ridge motif. Scoped, so the
   admin login is untouched.
   ══════════════════════════════════════════════════════════════════ */
.portal-app .auth-shell::before {
    background:
        radial-gradient(620px 380px at 16% 18%, rgb(var(--color-accent-rgb) / 0.18), transparent 56%),
        radial-gradient(520px 320px at 84% 82%, rgb(var(--color-cta-rgb) / 0.14), transparent 58%),
        radial-gradient(820px 520px at 50% 112%, rgb(var(--color-accent-rgb) / 0.06), transparent 62%);
}
.portal-app .auth-card {
    position: relative;
    overflow: hidden;
}
/* Ridge accent crowning the card's top edge. */
.portal-app .auth-card::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: linear-gradient(90deg,
        transparent 0%,
        rgb(var(--color-accent-rgb) / 0.65) 16%,
        var(--color-accent) 40%,
        var(--color-cta) 50%,
        var(--color-accent) 60%,
        rgb(var(--color-accent-rgb) / 0.65) 84%,
        transparent 100%);
}


/* ══════════════════════════════════════════════════════════════════
   10 · ERROR PAGES + EMPTY-STATE MOTIF — alpine contour lines
   ══════════════════════════════════════════════════════════════════ */

/* Portal error pages render inside the layout chrome, so cap the hero height
   (the shared rule is 100vh, which would overflow past topbar + footer). */
.portal-app .error-hero {
    min-height: min(72vh, 560px);
    position: relative;
    isolation: isolate;
}
/* Faint contour ridgeline behind the error code (mask → recolors with theme). */
.portal-app .error-hero::before {
    content: "";
    position: absolute;
    inset: auto 0 12% 0;
    height: 180px;
    z-index: -1;
    opacity: 0.5;
    background-color: var(--color-accent);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='480' height='180' viewBox='0 0 480 180' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M0 150 96 64 168 112 264 32 360 92 480 24' opacity='0.55'/%3E%3Cpath d='M0 176 96 104 168 140 264 76 360 120 480 64' opacity='0.32'/%3E%3C/svg%3E") center bottom / 880px auto no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='480' height='180' viewBox='0 0 480 180' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M0 150 96 64 168 112 264 32 360 92 480 24' opacity='0.55'/%3E%3Cpath d='M0 176 96 104 168 140 264 76 360 120 480 64' opacity='0.32'/%3E%3C/svg%3E") center bottom / 880px auto no-repeat;
}
.portal-app .error-hero__code {
    font-family: var(--font-display);
    font-variation-settings: 'opsz' 80;
    background: linear-gradient(180deg, var(--color-accent), var(--color-cta));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
.portal-app .error-hero__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-3xl);
    font-variation-settings: 'opsz' 30;
    letter-spacing: var(--ls-tight);
}

/* Empty states: a faint contour ridge above the icon for alpine character. */
.portal-app .empty-state {
    position: relative;
    overflow: hidden;
}
.portal-app .empty-state::before {
    content: "";
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 280px;
    height: 70px;
    opacity: 0.45;
    pointer-events: none;
    background-color: var(--color-accent);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='280' height='70' viewBox='0 0 280 70' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M0 56 64 22 108 44 160 10 212 38 280 8' opacity='0.55'/%3E%3Cpath d='M0 68 64 40 108 58 160 30 212 52 280 28' opacity='0.32'/%3E%3C/svg%3E") center top / contain no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='280' height='70' viewBox='0 0 280 70' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M0 56 64 22 108 44 160 10 212 38 280 8' opacity='0.55'/%3E%3Cpath d='M0 68 64 40 108 58 160 30 212 52 280 28' opacity='0.32'/%3E%3C/svg%3E") center top / contain no-repeat;
}
.portal-app .empty-state__icon {
    position: relative;
    color: var(--color-accent);
    background: var(--color-accent-bg);
    border-color: rgb(var(--color-accent-rgb) / 0.22);
}
.portal-app .empty-state__body { max-width: 44ch; }


/* ══════════════════════════════════════════════════════════════════
   11 · REFERRAL SHARE CARDS — portal "Empfehlungslinks"
   Each campaign link is a share artifact: a ridge-crowned card pairing a
   wrap-safe link field + visit chip with a framed, scannable QR plate. The
   old markup let long URLs escape the tile in a narrow 3-up grid; this gives
   each card room and forces the URL to break. Scoped to .portal-app so the
   admin referral views are untouched.
   ══════════════════════════════════════════════════════════════════ */
.portal-app .referral-link-grid {
    display: grid;
    gap: 1.25rem;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 380px), 1fr));
}

.portal-app .referral-share-card {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 1.25rem 1.5rem;
    padding: 1.375rem 1.375rem 1.25rem;
    background: var(--color-bg-elevated);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
    transition: transform var(--dur) var(--ease-out),
                border-color var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out);
}
/* Ridge motif crowning the card's top edge, echoing the auth card. */
.portal-app .referral-share-card::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    opacity: 0.9;
    background: linear-gradient(90deg,
        transparent 0%,
        rgb(var(--color-accent-rgb) / 0.65) 16%,
        var(--color-accent) 40%,
        var(--color-cta) 50%,
        var(--color-accent) 60%,
        rgb(var(--color-accent-rgb) / 0.65) 84%,
        transparent 100%);
}
/* Faint moss aura tucked behind the QR corner. */
.portal-app .referral-share-card::after {
    content: "";
    position: absolute;
    z-index: -1;
    top: -35%;
    right: -18%;
    width: 260px;
    height: 260px;
    pointer-events: none;
    background: radial-gradient(circle at center, rgb(var(--color-accent-rgb) / 0.10), transparent 68%);
}
.portal-app .referral-share-card:hover {
    transform: translateY(-3px);
    border-color: rgb(var(--color-accent-rgb) / 0.32);
    box-shadow: var(--shadow-overlay);
}

.portal-app .referral-share-card__main {
    flex: 1 1 220px;
    min-width: 0;               /* lets the link field wrap instead of overflowing */
    display: flex;
    flex-direction: column;
    gap: 0.875rem;
    align-self: stretch;
}

.portal-app .referral-share-card__head {
    display: flex;
    align-items: center;
    gap: 0.625rem;
}
.portal-app .referral-share-card__glyph {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: var(--radius-md);
    color: var(--color-accent);
    background: var(--color-accent-bg);
    border: 1px solid rgb(var(--color-accent-rgb) / 0.22);
}
.portal-app .referral-share-card__glyph svg { width: 1.15rem; height: 1.15rem; }
.portal-app .referral-share-card__title {
    margin: 0;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-lg);
    font-variation-settings: 'opsz' 20;
    letter-spacing: var(--ls-tight);
    line-height: var(--lh-snug);
    color: var(--color-fg-primary);
    overflow-wrap: anywhere;
}

/* Link field — inset, mono, wrap-safe. The core overflow fix. */
.portal-app .referral-link-field {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.625rem 0.75rem;
    background: var(--color-bg-inset);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
}
.portal-app .referral-link-field__icon {
    flex-shrink: 0;
    width: 0.9rem;
    height: 0.9rem;
    margin-top: 0.15rem;
    color: var(--color-fg-tertiary);
}
.portal-app .referral-link-field__url {
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    line-height: 1.5;
    color: var(--color-fg-secondary);
    overflow-wrap: anywhere;    /* break long URLs so they never escape the card */
    word-break: break-word;
}

.portal-app .referral-share-card__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: auto;
}
.portal-app .referral-share-card__copy { flex-shrink: 0; }

/* Visit chip — mono number, micro uppercase label. */
.portal-app .referral-visits {
    display: inline-flex;
    align-items: baseline;
    gap: 0.375rem;
    font-family: var(--font-mono);
}
.portal-app .referral-visits__icon {
    width: 0.85rem;
    height: 0.85rem;
    align-self: center;
    color: var(--color-fg-tertiary);
}
.portal-app .referral-visits__count {
    font-size: var(--fs-sm);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--color-fg-primary);
}
.portal-app .referral-visits__label {
    font-size: var(--fs-2xs);
    letter-spacing: var(--ls-wide);
    text-transform: uppercase;
    color: var(--color-fg-tertiary);
}

/* QR plate — always a white, rounded, softly-shadowed plaque so the code
   stays scannable in both themes (QR is black-on-white). */
.portal-app .referral-qr-plate {
    flex: 0 0 auto;
    margin: 0 auto;
    padding: 0.75rem;
    background: #ffffff;
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    line-height: 0;
}
.portal-app .referral-qr {
    display: block;
    width: 140px;
    height: 140px;
    border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
    .portal-app .referral-share-card { transition: none; }
    .portal-app .referral-share-card:hover { transform: none; }
}
