/* ===========================================================================
   Coupon Affiliates (Local) — portal stylesheet (simplified portal)
   ---------------------------------------------------------------------------
   Renders every portal page: login, forgot password, reset, dashboard.
   Tokens mirror the WP 404 template and the Astro shopEsim frontend —
   cream + charcoal + Inter, with brand accents in teal, bronze and
   purple that match the dashboard mock-up.

   2026-08-04 simplification: trimmed from 1799 lines and re-built
   around the new 2-tab structure. Every class the dashboard shortcode
   emits is styled here; the login / forgot / reset shortcodes share
   the same primitives (form, button, notice, card) so no second pass
   is needed.
   =========================================================================== */

:root {
    --cal-cream:            #f7f4ed;
    --cal-charcoal:         #1c1c1c;
    --cal-off-white:        #fcfbf8;
    --cal-light-cream:      #eceae4;
    --cal-muted-gray:       #5f5f5d;
    --cal-soft-gray:        #8a8a87;
    --cal-interactive-bdr:  rgba(28, 28, 28, 0.32);
    --cal-shadow-card:      0 2px 6px rgba(28, 28, 28, 0.05), 0 1px 2px rgba(28, 28, 28, 0.04);
    --cal-shadow-card-hover:0 6px 18px rgba(28, 28, 28, 0.08), 0 2px 4px rgba(28, 28, 28, 0.05);
    --cal-shadow-focus:     0 0 0 3px rgba(0, 140, 110, 0.25);

    --cal-radius-sm:   8px;
    --cal-radius-md:  12px;
    --cal-radius-lg:  16px;
    --cal-radius-xl:  20px;
    --cal-radius-pill: 9999px;

    /* Brand accents — matched to the mock-up so the portal feels like
       one product next to the Astro shopEsim frontend. */
    --cal-brand-bronze:      #D48A3A;
    --cal-brand-bronze-dark: #b8702b;
    --cal-brand-teal:        #008C6E;
    --cal-brand-teal-dark:   #006b54;
    --cal-brand-purple:      #3d19cb;
    --cal-brand-purple-dark: #2c1099;

    --cal-font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

    /* Form spacing token — every gap in a form (form ↔ form-row ↔
       field-group ↔ label↔input) is derived from this so the rhythm
       is uniform. Bump this once to re-space all forms. */
    --cal-portal-form-gap: 1.5rem;
}

/* Reset only inside the portal body so we don't drag WP defaults onto the page. */
body.cal-portal-body {
    margin: 0;
    background: var(--cal-cream);
    color: var(--cal-charcoal);
    font-family: var(--cal-font-family);
    font-size: 16px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

a { color: inherit; }

/* ===========================================================================
   Page chrome — header (logo + nav) and footer
   =========================================================================== */
.cal-portal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.25rem 2rem;
    width: 100%;
    box-sizing: border-box;
    background: var(--cal-off-white);
    border-bottom: 1px solid var(--cal-light-cream);
    box-shadow: var(--cal-shadow-card);
    position: sticky;
    top: 0;
    z-index: 10;
}
.cal-portal-brand {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
    color: inherit;
}
.cal-portal-brand:hover { opacity: 0.85; }
.cal-portal-logo {
    display: block;
    height: auto;
    max-height: 72px;
    width: auto;
}
.cal-portal-nav {
    display: flex;
    align-items: center;
    gap: 1.25rem;
}
.cal-portal-nav-link {
    color: var(--cal-charcoal);
    text-decoration: none;
    font-weight: 500;
    font-size: 0.95rem;
    padding: 0.4rem 0.85rem;
    border-radius: var(--cal-radius-pill);
    transition: background-color 0.15s ease;
}
.cal-portal-nav-link:hover { background: var(--cal-light-cream); text-decoration: none; }
.cal-portal-nav-user {
    color: var(--cal-muted-gray);
    font-size: 0.9rem;
    margin-right: 0.25rem;
}

/* Fixed shell width per breakpoint instead of `width: auto`, so the
   layout never resizes when switching tabs — the content of the open
   <details> can no longer influence it.
   `max-width: 100%` is the safety net: when the viewport is narrower
   than the fixed width the shell clamps to it instead of overflowing.
   `box-sizing: border-box` keeps the 1.25rem side padding inside the
   declared width (there is no global border-box reset in this file),
   so desktop is 960px edge-to-edge, not 1000px. */
.cal-portal-main {
    width: 960px;
    max-width: 100%;
    box-sizing: border-box;
    margin: 0 auto;
    padding: 2.5rem 1.25rem 4rem;
    flex: 1 1 auto;
}
/* Tablet. */
@media (max-width: 1023px) {
    .cal-portal-main { width: 900px; }
}
/* Phone: fluid on purpose — device widths run 320-430px, so any fixed
   value would either overflow the small ones or waste space on the
   large ones. The side padding provides the gutter; the responsive
   padding itself is set further down with the other mobile chrome
   rules, so only the width is declared here. */
@media (max-width: 640px) {
    .cal-portal-main { width: 100%; }
}

.cal-portal-footer {
    border-top: 1px solid var(--cal-light-cream);
    padding: 1.5rem 2rem;
    text-align: center;
    color: var(--cal-muted-gray);
    font-size: 0.85rem;
    background: var(--cal-off-white);
}
.cal-portal-footer-text { margin: 0; }

/* ===========================================================================
   Section / card primitives — reused by dashboard, login, forgot, reset
   =========================================================================== */
.cal-portal-section {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}
.cal-portal-section-title {
    margin: 0 0 0.75rem;
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--cal-charcoal);
}
.cal-portal-h1 {
    margin: 0;
    font-size: clamp(1.65rem, 4vw, 2.1rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.15;
}
.cal-portal-subhead {
    margin: 0;
    color: var(--cal-muted-gray);
    font-size: 1rem;
    line-height: 1.55;
}

.cal-portal-card {
    background: var(--cal-off-white);
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-lg);
    padding: 1.5rem 1.75rem;
    box-shadow: var(--cal-shadow-card);
    transition: box-shadow 0.18s ease, transform 0.18s ease;
    box-sizing: border-box;
}
.cal-portal-card:hover { box-shadow: var(--cal-shadow-card-hover); }
.cal-portal-card-title {
    margin: 0 0 0.4rem;
    font-size: 1.15rem;
    font-weight: 600;
    letter-spacing: -0.01em;
}
.cal-portal-card-sub {
    margin: 0 0 1rem;
    color: var(--cal-muted-gray);
    font-size: 0.92rem;
    line-height: 1.5;
}

/* ===========================================================================
   Forms — inputs, selects, checkboxes, full-width button row
   ===========================================================================
   Sizing tokens: every gap in a form (.cal-portal-form, .cal-portal-form-row,
   the per-method field group, and the label↔input inside .cal-portal-form-field)
   is derived from --cal-portal-form-gap so the rhythm is uniform across
   Personal / Payment / login / forgot / reset. Adjust the variable once
   and the whole portal re-spaces. */
.cal-portal-form {
    display: flex;
    flex-direction: column;
    gap: var(--cal-portal-form-gap);
}
.cal-portal-form-field {
    display: flex;
    flex-direction: column;
    gap: var(--cal-portal-form-gap);
}
.cal-portal-form-field label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--cal-charcoal);
    letter-spacing: 0.01em;
}
/* Raw form controls inside a .cal-portal-form-field: the user info and
   payment forms render their <input>/<select>/<textarea> without
   explicit modifier classes, so we style by descendant selector. The
   explicit .cal-portal-form-input/-select/-textarea classes still work
   for any form that opts in. */
.cal-portal-form-field input[type="text"],
.cal-portal-form-field input[type="email"],
.cal-portal-form-field input[type="tel"],
.cal-portal-form-field input[type="url"],
.cal-portal-form-field input[type="number"],
.cal-portal-form-field input[type="password"],
.cal-portal-form-field input:not([type]),
.cal-portal-form-field select,
.cal-portal-form-field textarea,
.cal-portal-form-input,
.cal-portal-form-textarea,
.cal-portal-form-select {
    width: 100%;
    padding: 0.7rem 0.95rem;
    border: 1px solid var(--cal-interactive-bdr);
    border-radius: var(--cal-radius-md);
    background: var(--cal-off-white);
    color: var(--cal-charcoal);
    font: inherit;
    font-size: 0.95rem;
    box-sizing: border-box;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
}
.cal-portal-form-field select,
.cal-portal-form-select {
    /* Inline SVG caret so the native OS arrow doesn't sit on top of
       the rounded corner / padding. */
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%231c1c1c' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><polyline points='1,1.5 6,6.5 11,1.5'/></svg>");
    background-repeat: no-repeat;
    background-position: right 0.95rem center;
    background-size: 12px 8px;
    padding-right: 2.4rem;
    cursor: pointer;
}
.cal-portal-form-field textarea,
.cal-portal-form-textarea { min-height: 110px; resize: vertical; }
.cal-portal-form-field input[type="text"]:hover,
.cal-portal-form-field input[type="email"]:hover,
.cal-portal-form-field input[type="tel"]:hover,
.cal-portal-form-field input[type="url"]:hover,
.cal-portal-form-field input[type="number"]:hover,
.cal-portal-form-field input[type="password"]:hover,
.cal-portal-form-field input:not([type]):hover,
.cal-portal-form-field select:hover,
.cal-portal-form-field textarea:hover,
.cal-portal-form-input:hover,
.cal-portal-form-textarea:hover,
.cal-portal-form-select:hover {
    border-color: rgba(28, 28, 28, 0.55);
}
.cal-portal-form-field input[type="text"]:focus,
.cal-portal-form-field input[type="email"]:focus,
.cal-portal-form-field input[type="tel"]:focus,
.cal-portal-form-field input[type="url"]:focus,
.cal-portal-form-field input[type="number"]:focus,
.cal-portal-form-field input[type="password"]:focus,
.cal-portal-form-field input:not([type]):focus,
.cal-portal-form-field select:focus,
.cal-portal-form-field textarea:focus,
.cal-portal-form-input:focus,
.cal-portal-form-textarea:focus,
.cal-portal-form-select:focus {
    outline: none;
    border-color: var(--cal-brand-teal);
    box-shadow: var(--cal-shadow-focus);
}
.cal-portal-form-hint {
    margin: 0.25rem 0 0;
    color: var(--cal-muted-gray);
    font-size: 0.82rem;
    line-height: 1.4;
}
.cal-portal-form-row {
    display: flex;
    gap: var(--cal-portal-form-gap);
    flex-wrap: wrap;
}
/* Half-field basis is `(row-width − row-gap) / 2` so two halves plus
   the gap fit exactly into the row at any gap value. The previous
   hard-coded `calc(50% - 0.5rem)` only summed correctly at gap=1rem
   and overflowed by 0.5rem at gap=1.5rem, which is what was
   pushing País + Divisa onto two lines. */
.cal-portal-form-field--half {
    flex: 1 1 calc((100% - var(--cal-portal-form-gap)) / 2);
    min-width: 12rem;
}
/* Per-method field group inside the payment form. Same flex-column
   rhythm as the parent form so fields inside a (country, method) combo
   have the same spacing as fields outside the wrapper.
   The :not([hidden]) guard is critical: the JS swap uses the `hidden`
   attribute to hide non-matching groups, but a plain `[data-cal-payment-fields]
   { display: flex }` rule would override `[hidden] { display: none }` and
   keep every group always visible. The :not() keeps the flex layout only
   when the group is meant to show. */
[data-cal-payment-fields]:not([hidden]) {
    display: flex;
    flex-direction: column;
    gap: var(--cal-portal-form-gap);
}
.cal-portal-form-checkbox {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    font-size: 0.92rem;
    color: var(--cal-charcoal);
    cursor: pointer;
}
.cal-portal-form-checkbox input {
    width: 1.05rem;
    height: 1.05rem;
    accent-color: var(--cal-brand-teal);
}

/* ===========================================================================
   Buttons — primary (charcoal), secondary (outline), small variants
   =========================================================================== */
.cal-portal-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.7rem 1.5rem;
    background: var(--cal-charcoal);
    color: var(--cal-off-white);
    border: 1px solid var(--cal-charcoal);
    border-radius: var(--cal-radius-pill);
    font: inherit;
    font-weight: 600;
    font-size: 0.95rem;
    cursor: pointer;
    text-decoration: none;
    transition: background-color 0.15s ease, transform 0.05s ease, box-shadow 0.15s ease;
}
.cal-portal-button:hover {
    background: #2a2a2a;
    border-color: #2a2a2a;
    color: var(--cal-off-white);
    text-decoration: none;
}
.cal-portal-button:active { transform: translateY(1px); }
.cal-portal-button:focus-visible {
    outline: none;
    box-shadow: var(--cal-shadow-focus);
}
.cal-portal-button--full { width: 100%; }
.cal-portal-button--secondary {
    background: transparent;
    color: var(--cal-charcoal);
    border-color: var(--cal-interactive-bdr);
}
.cal-portal-button--secondary:hover {
    background: var(--cal-light-cream);
    border-color: var(--cal-interactive-bdr);
    color: var(--cal-charcoal);
}
.cal-portal-button--small {
    padding: 0.4rem 1rem;
    font-size: 0.85rem;
}
.cal-portal-button--teal {
    background: var(--cal-brand-teal);
    border-color: var(--cal-brand-teal);
}
.cal-portal-button--teal:hover {
    background: var(--cal-brand-teal-dark);
    border-color: var(--cal-brand-teal-dark);
    color: #fff;
}
.cal-portal-button--purple {
    background: var(--cal-brand-purple);
    border-color: var(--cal-brand-purple);
}
.cal-portal-button--purple:hover {
    background: var(--cal-brand-purple-dark);
    border-color: var(--cal-brand-purple-dark);
    color: #fff;
}
/* Brief flash on the copy buttons after a successful click. */
.cal-portal-copy-ok {
    background: var(--cal-brand-teal) !important;
    color: #fff !important;
    border-color: var(--cal-brand-teal) !important;
}

/* ===========================================================================
   Notices — paused/suspended banner, save confirmations, info messages
   =========================================================================== */
.cal-portal-notice {
    border-radius: var(--cal-radius-md);
    padding: 0.95rem 1.15rem;
    font-size: 0.92rem;
    line-height: 1.5;
    border: 1px solid transparent;
    background: var(--cal-off-white);
}
.cal-portal-notice strong { display: block; margin-bottom: 0.15rem; font-weight: 700; }
.cal-portal-notice--success { background: #e6f4ee; border-color: #b9dccb; color: #14532d; }
.cal-portal-notice--error   { background: #fde7e7; border-color: #f3b3b3; color: #7a1313; }
.cal-portal-notice--warning { background: #fff4e0; border-color: #f1d8a8; color: #6b4413; }
.cal-portal-notice--info    { background: #eef3fb; border-color: #c5d5ed; color: #1f3b6b; }

/* ===========================================================================
   Tab nav + <details> — pill navigation, content rendered open
   =========================================================================== */
.cal-portal-tabs {
    display: inline-flex;
    gap: 0.4rem;
    padding: 0.45rem;
    background: var(--cal-off-white);
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-pill);
    align-self: center;
    box-shadow: var(--cal-shadow-card);
}
.cal-portal-tab-link {
    display: inline-flex;
    align-items: center;
    padding: 0.5rem 1.4rem;
    border-radius: var(--cal-radius-pill);
    color: var(--cal-charcoal);
    text-decoration: none;
    font-size: 0.92rem;
    font-weight: 600;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.cal-portal-tab-link:hover {
    background: var(--cal-light-cream);
    color: var(--cal-charcoal);
    text-decoration: none;
}
.cal-portal-tab-link--active {
    background: var(--cal-charcoal);
    color: var(--cal-off-white);
}
.cal-portal-tab-link--active:hover {
    background: #2a2a2a;
    color: var(--cal-off-white);
}
.cal-portal-details {
    background: transparent;
    border: none;
    margin: 0;
    padding: 0;
}
.cal-portal-details[open] { background: transparent; }
/* Closed <details> blocks still count as flex siblings of the section
   (gap: 1.5rem), so when Ventas is closed and Información opens, the
   gap is added twice (once for the empty Ventas, once for Información)
   and the tabs feel unevenly spaced. Hiding the closed ones collapses
   the gap so the active tab's content sits flush below the tabs.
   Safe because the summary is already display:none — the <details> is
   not focusable anyway. */
.cal-portal-details:not([open]) {
    display: none;
}
.cal-portal-summary {
    display: none; /* tab bodies render open via the JS switcher; the
                      <summary> marker is hidden but the <details>
                      stays focusable for accessibility. */
}

/* ===========================================================================
   Partner data (read-only) — three rows inside Información
   ===========================================================================
   Span the full grid width: Personal + Payment sit side-by-side on
   row 1, but the partner data and the action row are full-width
   sections below. Without `grid-column: 1 / -1` each would squeeze
   into one of the two columns and look orphaned. */
.cal-portal-informacion-grid > .cal-portal-section--profile,
.cal-portal-informacion-grid > .cal-portal-actions-row {
    grid-column: 1 / -1;
}
.cal-portal-section--profile {
    background: var(--cal-off-white);
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-lg);
    box-shadow: var(--cal-shadow-card);
    padding: 1.5rem 1.75rem;
    margin-top: 0.75rem;
    box-sizing: border-box;
}
.cal-portal-profile-grid {
    display: flex;
    flex-direction: column;
    margin-top: 0.5rem;
}
.cal-portal-profile-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.85rem 0;
    border-bottom: 1px solid var(--cal-light-cream);
}
.cal-portal-profile-row:last-child { border-bottom: none; }
.cal-portal-profile-label {
    color: var(--cal-muted-gray);
    font-size: 0.88rem;
    font-weight: 500;
}
.cal-portal-profile-value {
    font-weight: 700;
    color: var(--cal-charcoal);
    font-size: 1rem;
    text-align: right;
}

/* ===========================================================================
   Header additions — partner level chip + affiliate link / coupon block
   =========================================================================== */
/* Header card — wraps the level chip and the affiliate link/coupon
   block. Same visual treatment as .cal-portal-card so the dashboard
   reads as one uniform stack of cards from top to bottom. The level
   chip floats at the top-left; the affiliate block fills the rest
   with no card-of-its-own so we don't get nested cards. */
.cal-portal-affiliate-row-wrap {
    background: var(--cal-off-white);
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-lg);
    box-shadow: var(--cal-shadow-card);
    padding: 1.5rem 1.75rem;
    display: flex;
    flex-direction: column;
    gap: 1rem;
    width: 100%;
    box-sizing: border-box;
    margin: 0;
    transition: box-shadow 0.18s ease, transform 0.18s ease;
}
.cal-portal-affiliate-row-wrap:hover {
    box-shadow: var(--cal-shadow-card-hover);
}
.cal-portal-affiliate-row-wrap > .cal-portal-level {
    align-self: flex-start;
    box-shadow: none;
    background: transparent;
    border: none;
    padding: 0;
}
/* The affiliate block used to carry its own card styling — strip it
   now that the wrap is the surrounding card. Keeps the curl info
   inside the same visual unit as the chip. */
.cal-portal-affiliate-row-wrap > .cal-portal-affiliate-block {
    background: transparent;
    border: none;
    border-radius: 0;
    padding: 0;
    box-shadow: none;
    width: 100%;
}
.cal-portal-affiliate-row-wrap > .cal-portal-level {
    align-self: flex-start;
}
.cal-portal-affiliate-row-wrap > .cal-portal-affiliate-block {
    width: 100%;
}
.cal-portal-level {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.65rem 1.1rem;
    background: var(--cal-off-white);
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-pill);
    font-size: 0.95rem;
    align-self: flex-start;
    box-shadow: var(--cal-shadow-card);
}
.cal-portal-level-label { color: var(--cal-charcoal); font-weight: 500; }
.cal-portal-level-chip {
    background: var(--cal-brand-bronze);
    color: #fff;
    padding: 3px 12px;
    border-radius: var(--cal-radius-pill);
    font-weight: 700;
    letter-spacing: 0.05em;
    font-size: 0.78rem;
    text-transform: uppercase;
}
.cal-portal-level-info {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.7rem;
    height: 1.7rem;
    background: transparent;
    border: none;
    color: var(--cal-muted-gray);
    border-radius: 50%;
    cursor: pointer;
    margin-left: 0.15rem;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.cal-portal-level-info:hover {
    background: var(--cal-light-cream);
    color: var(--cal-charcoal);
}
.cal-portal-level-info:focus-visible {
    outline: none;
    box-shadow: var(--cal-shadow-focus);
}

.cal-portal-affiliate-block {
    background: var(--cal-off-white);
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-lg);
    padding: 1.5rem 1.75rem;
    box-shadow: var(--cal-shadow-card);
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.cal-portal-affiliate-row {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}
.cal-portal-affiliate-label {
    flex: 0 0 11rem;
    font-weight: 700;
    color: var(--cal-charcoal);
    font-size: 0.95rem;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    flex-wrap: wrap;
}
.cal-portal-affiliate-value {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    flex: 1 1 auto;
    min-width: 0;
}
/* Push the FIRST action button (Copiar / Crear Código) to the right
   end of the value row so the URL/coupon stays at its natural width
   on the left and the button group sits flush right. Only the first
   button gets `margin-left: auto` — if every button had it, flexbox
   would distribute the available space between each pair, splitting
   the button group across the row instead of grouping them.
   flex-shrink:0 keeps the button from being squashed when the URL
   truncates. The `gap` on the parent then keeps subsequent buttons
   flush against the first. */
.cal-portal-affiliate-value > .cal-portal-button:first-of-type,
.cal-portal-affiliate-value > .cal-portal-affiliate-gen:first-of-type {
    margin-left: auto;
    flex-shrink: 0;
}
.cal-portal-affiliate-link {
    color: var(--cal-brand-teal);
    text-decoration: none;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 1 1 auto;
}
.cal-portal-affiliate-link:hover {
    color: var(--cal-brand-teal-dark);
    text-decoration: underline;
}
/* Inactive state: the link still renders with the coupon code so the
   partner can see what their code is, but it looks inert because the
   code is pending or rejected. The persistent notice above the link
   explains the reason. */
.cal-portal-affiliate-link--inactive {
    color: var(--cal-soft-gray);
    cursor: not-allowed;
    text-decoration: line-through;
    text-decoration-color: var(--cal-light-cream);
    text-decoration-thickness: 1px;
}
.cal-portal-affiliate-link--inactive:hover {
    color: var(--cal-soft-gray);
    text-decoration: line-through;
    text-decoration-color: var(--cal-light-cream);
}
.cal-portal-affiliate-gen { margin: 0; display: inline-flex; }
.cal-portal-coupon-code-display {
    font-weight: 700;
    color: var(--cal-brand-purple);
    background: rgba(61, 25, 203, 0.08);
    padding: 5px 12px;
    border-radius: var(--cal-radius-sm);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.95rem;
    border: 1px solid rgba(61, 25, 203, 0.18);
}
.cal-portal-coupon-code-display--pending {
    color: #b8702b;
    background: rgba(216, 138, 58, 0.12);
    border: 1px solid rgba(216, 138, 58, 0.25);
}
.cal-portal-coupon-code-display--rejected {
    color: #7a1313;
    background: rgba(253, 224, 224, 0.6);
    border: 1px solid rgba(243, 179, 179, 0.6);
    text-decoration: line-through;
}
.cal-portal-coupon-status {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.88rem;
}
.cal-portal-coupon-status-label {
    color: var(--cal-muted-gray);
    font-weight: 500;
}
.cal-portal-coupon-status-value {
    font-weight: 700;
}
.cal-portal-coupon-status-value--pending { color: #b8702b; }
.cal-portal-coupon-status-value--rejected { color: #7a1313; }
.cal-portal-coupon-empty {
    color: var(--cal-brand-purple);
    font-weight: 600;
    font-size: 0.92rem;
}
.cal-portal-affiliate-row--coupon .cal-portal-affiliate-value {
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

/* Admin-side badge used inside the user-edit form. */
.cal-partner-coupon-status-badge {
    display: inline-block;
    padding: 2px 10px;
    border-radius: var(--cal-radius-pill);
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    background: var(--cal-light-cream);
    color: var(--cal-charcoal);
    margin-left: 6px;
}
.cal-partner-coupon-status-badge--pending  { background: #fdf0d6; color: #6b4413; }
.cal-partner-coupon-status-badge--approved { background: #d6efd8; color: #1d5b27; }
.cal-partner-coupon-status-badge--rejected { background: #fde0e0; color: #7a1313; }

/* ===========================================================================
   Coupon modals — edit-confirmation + choose-code
   =========================================================================== */
/* The modal element is `position: fixed` covering the viewport; the
   panel sits centered, the backdrop absorbs clicks to close. */
.cal-portal-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
}
.cal-portal-modal[hidden] { display: none; }
.cal-portal-modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(28, 28, 28, 0.55);
    cursor: pointer;
}
.cal-portal-modal__panel {
    position: relative;
    background: #ffffff;
    border: 2px solid var(--cal-brand-teal);
    border-radius: var(--cal-radius-lg);
    padding: 1rem 1.25rem;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    max-height: min(600px, calc(100vh - 2rem));
    overflow-y: auto;
    width: calc(100% - 2rem);
    max-width: 33rem;
    box-sizing: border-box;
    color: #1c1c1c;
    /* Hide the scrollbar visually while keeping it functional — the
       mock used a .hideScrollbar utility; we emulate it cross-browser. */
    scrollbar-width: thin;
    scrollbar-color: var(--cal-light-cream) transparent;
}
.cal-portal-modal__panel::-webkit-scrollbar { width: 6px; }
.cal-portal-modal__panel::-webkit-scrollbar-thumb {
    background: var(--cal-light-cream);
    border-radius: 3px;
}
.cal-portal-modal__panel--narrow { gap: 1rem; }
.cal-portal-modal__close {
    position: absolute;
    top: 0.6rem;
    right: 0.6rem;
    background: transparent;
    border: none;
    color: #1c1c1c;
    cursor: pointer;
    padding: 0.3rem;
    border-radius: 50%;
    line-height: 0;
    transition: background-color 0.15s ease;
}
.cal-portal-modal__close:hover {
    background: var(--cal-light-cream);
}
.cal-portal-modal__close:focus-visible {
    outline: none;
    box-shadow: var(--cal-shadow-focus);
}
.cal-portal-modal__title {
    margin: 0;
    padding-right: 1.75rem; /* leave room for the X */
    font-size: 1.2rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.3;
    color: #1c1c1c;
}
.cal-portal-modal p {
    margin: 0;
    color: #1c1c1c;
    font-size: 0.92rem;
    line-height: 1.5;
    text-align: left;
}
.cal-portal-modal__form {
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
}
.cal-portal-modal__input {
    width: 100%;
    box-sizing: border-box;
    padding: 0.55rem 0.85rem;
    border: 2px solid #6b6b6b;
    border-radius: var(--cal-radius-md);
    background: #ffffff;
    color: #1c1c1c;
    font: inherit;
    font-size: 0.95rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.cal-portal-modal__input:hover { border-color: #1c1c1c; }
.cal-portal-modal__input:focus {
    outline: none;
    border-color: var(--cal-brand-teal);
    box-shadow: var(--cal-shadow-focus);
}
.cal-portal-modal__error {
    margin: 0;
    padding: 0.55rem 0.75rem;
    background: #fde7e7;
    border: 1px solid #f3b3b3;
    border-radius: var(--cal-radius-sm);
    color: #7a1313;
    font-size: 0.88rem;
}
.cal-portal-modal__actions {
    display: flex;
    flex-direction: row;
    justify-content: flex-end;
    align-items: center;
    width: 100%;
}
.cal-portal-modal__cta {
    min-width: 11rem;
    padding: 0.4rem 0.85rem;
    font-weight: 600;
    border-radius: 12px;
    line-height: 1.3;
    /* Buttons in the portal are charcoal — matches the rest of the
       .cal-portal-button family. The mock's teal was a leftover from
       the Astro frontend design system; the WordPress portal's
       actual brand is charcoal #1c1c1c. */
    background: var(--cal-charcoal);
    border-color: var(--cal-charcoal);
    color: #ffffff;
}
.cal-portal-modal__cta:hover {
    background: #2a2a2a;
    border-color: #2a2a2a;
    color: #ffffff;
}

/* Wide modal — used by the levels table which needs more horizontal
   space than the coupon modals. Matches the mock's lg:w-[50rem]. */
.cal-portal-modal__panel--wide {
    max-width: 50rem;
    padding: 1rem 1.25rem;
}
@media (min-width: 1024px) {
    .cal-portal-modal__panel--wide {
        padding: 1.5rem 1.75rem;
    }
}
.cal-portal-modal__link {
    color: #1c1c1c;
    text-decoration: underline;
    text-underline-offset: 2px;
    font-weight: 600;
}
.cal-portal-modal__link:hover {
    color: var(--cal-brand-teal);
}

/* Levels grid — 4 per-tier cards. On desktop the cards sit side-by-side
   so the partner scans the tiers horizontally and the metrics stack
   inside each card. On mobile (≤640px) the cards collapse to a single
   column so each tier reads as one self-contained block. The
   per-card layout works on every viewport without the awkward
   row-stacking that the previous table-style markup produced. */
.cal-portal-levels-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0.75rem;
    margin: 0.5rem 0 1rem;
    width: 100%;
}
.cal-portal-level-card {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    background: var(--cal-cream);
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-md);
    padding: 0.9rem 0.95rem;
}
.cal-portal-level-card__head {
    display: flex;
    justify-content: center;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--cal-light-cream);
}
.cal-portal-level-card__metric {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    text-align: center;
}
.cal-portal-level-card__metric-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--cal-muted-gray);
    font-weight: 600;
}
.cal-portal-level-card__metric-value {
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--cal-charcoal);
    font-variant-numeric: tabular-nums;
}
.cal-portal-levels-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.4rem 1rem;
    color: #1c1c1c;
    border: 2px solid rgba(0, 0, 0, 0.45);
    border-radius: var(--cal-radius-xl);
    font-weight: 700;
    font-size: 0.95rem;
    text-align: center;
}

/* Tablet: 2x2 grid so cards stay readable on iPad-sized viewports
   without horizontal scroll inside the wide modal panel. */
@media (max-width: 900px) {
    .cal-portal-levels-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.6rem;
    }
}

/* Phone: single column, full-width cards. Each tier is one block
   with the pill at the top and metrics stacked beneath. */
@media (max-width: 640px) {
    .cal-portal-levels-grid {
        grid-template-columns: 1fr;
        gap: 0.5rem;
    }
    .cal-portal-level-card {
        padding: 0.8rem 0.85rem;
    }
    .cal-portal-level-card__metric-label {
        font-size: 0.68rem;
    }
    .cal-portal-level-card__metric-value {
        font-size: 1rem;
    }
    .cal-portal-levels-pill {
        padding: 0.35rem 0.85rem;
        font-size: 0.88rem;
    }
}

/* ===========================================================================
   Ventas tab — commission summary tiles + month groups
   =========================================================================== */
/* Section headings use the shared .cal-portal-section-title primitive
   defined above with the card/section rules; only the "second heading
   in the same tab" gap lives here. */
.cal-portal-section-title--spaced { margin-top: 2rem; }
@media (max-width: 640px) {
    .cal-portal-section-title { font-size: 1.05rem; }
}

/* One card, three columns — not three cards. The metrics are three
   readings of the same balance (earned → paid → what's left), so they
   belong inside a single bordered block with hairline dividers rather
   than as separate tiles competing for attention. */
.cal-portal-ventas-summary {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    position: relative;
    background: var(--cal-off-white);
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-lg);
    box-shadow: var(--cal-shadow-card);
    overflow: hidden;
    transition: box-shadow 0.18s ease;
}
.cal-portal-ventas-summary:hover { box-shadow: var(--cal-shadow-card-hover); }
.cal-portal-ventas-tile {
    padding: 1.25rem 1.5rem;
    border-left: 1px solid var(--cal-light-cream);
}
.cal-portal-ventas-tile:first-child { border-left: none; }
/* Single column on phone: the dividers rotate from vertical to
   horizontal so the card still reads as three separated rows. The
   info button stays pinned to the card's top-right, which on this
   layout is the first row — so the reserved gutter moves with it. */
@media (max-width: 640px) {
    .cal-portal-ventas-summary { grid-template-columns: 1fr; }
    .cal-portal-ventas-tile {
        border-left: none;
        border-top: 1px solid var(--cal-light-cream);
    }
    .cal-portal-ventas-tile:first-child { border-top: none; }
    .cal-portal-ventas-tile:last-of-type { padding-right: 1.5rem; }
    .cal-portal-ventas-tile:first-child { padding-right: 2.75rem; }
}
.cal-portal-ventas-tile-value {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--cal-charcoal);
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
}
.cal-portal-ventas-tile-label {
    margin-top: 0.35rem;
    font-size: 0.85rem;
    color: var(--cal-muted-gray);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
}
/* Info button for the payouts modal: pinned to the card's top-right
   corner, out of the grid flow, at the same 1.7rem size as the levels
   button next to the tier chip. The last tile gets right padding so a
   long "Pendiente" figure never runs under it. */
.cal-portal-ventas-summary-info {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    margin-left: 0;
}
.cal-portal-ventas-tile:last-of-type { padding-right: 2.75rem; }

.cal-portal-ventas-months {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.cal-portal-ventas-month-block {
    background: var(--cal-off-white);
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-lg);
    padding: 1.25rem 1.5rem;
    box-shadow: var(--cal-shadow-card);
}
.cal-portal-ventas-month-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}
.cal-portal-ventas-month-title {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}
.cal-portal-month-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.45rem 1.05rem;
    background: var(--cal-charcoal);
    color: #fff;
    border: 1px solid var(--cal-charcoal);
    border-radius: var(--cal-radius-pill);
    font: inherit;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.15s ease;
}
.cal-portal-month-toggle:hover {
    background: #2a2a2a;
    border-color: #2a2a2a;
}
.cal-portal-month-toggle:focus-visible {
    outline: none;
    box-shadow: var(--cal-shadow-focus);
}
.cal-portal-ventas-month-block .cal-portal-table { margin-top: 1rem; }

/* ---------------------------------------------------------------------------
   Per-coupon summary card — sits directly under the 5-tile resumen
   so the partner sees the volume their specific code moved.
   --------------------------------------------------------------------------- */
.cal-portal-coupon-summary {
    margin-top: 1rem;
    background: var(--cal-off-white);
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-lg);
    padding: 1rem 1.5rem;
    box-shadow: var(--cal-shadow-card);
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.85rem 1.5rem;
}
@media (max-width: 640px) {
    .cal-portal-coupon-summary { grid-template-columns: 1fr; }
}
.cal-portal-coupon-summary-row {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.cal-portal-coupon-summary-label {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--cal-muted-gray);
    font-weight: 600;
}
.cal-portal-coupon-summary-value {
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--cal-charcoal);
    font-variant-numeric: tabular-nums;
}
.cal-portal-coupon-summary-value code {
    font-size: 1rem;
    background: var(--cal-light-cream);
    padding: 0.15rem 0.5rem;
    border-radius: 4px;
    letter-spacing: 0.05em;
}

/* ===========================================================================
   Tables — Ventas month tables + login errors
   =========================================================================== */
.cal-portal-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.92rem;
    background: var(--cal-cream);
    border-radius: var(--cal-radius-md);
    overflow: hidden;
}
.cal-portal-table th,
.cal-portal-table td {
    padding: 0.7rem 0.95rem;
    border-bottom: 1px solid var(--cal-light-cream);
    text-align: left;
}
.cal-portal-table th {
    font-weight: 700;
    color: var(--cal-muted-gray);
    font-size: 0.74rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    background: var(--cal-off-white);
}
.cal-portal-table tbody tr:last-child td { border-bottom: none; }
.cal-portal-table tbody tr:hover td { background: rgba(255, 255, 255, 0.6); }
.cal-portal-table-code {
    background: var(--cal-off-white);
    padding: 2px 8px;
    border-radius: var(--cal-radius-sm);
    font-size: 0.85em;
    border: 1px solid var(--cal-light-cream);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.cal-portal-table-empty {
    padding: 1.75rem 1.5rem;
    margin-top: 0.75rem;
    text-align: center;
    color: var(--cal-muted-gray);
    background: var(--cal-off-white);
    border: 1px dashed var(--cal-light-cream);
    border-radius: var(--cal-radius-md);
    font-size: 0.95rem;
}

/* Status pills — commission status inside the Ventas tables. */
.cal-portal-pill {
    display: inline-block;
    padding: 3px 10px;
    border-radius: var(--cal-radius-pill);
    font-size: 0.74rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    background: var(--cal-light-cream);
    color: var(--cal-charcoal);
}
.cal-portal-pill--paid          { background: #d6efd8; color: #1d5b27; }
.cal-portal-pill--unpaid        { background: #fdf0d6; color: #6b4413; }
.cal-portal-pill--partial       { background: #f3e1f0; color: #6b1a5c; }
.cal-portal-pill--void          { background: #fde0e0; color: #7a1313; }
.cal-portal-pill--void_post_pay { background: #fde0e0; color: #7a1313; }

/* ===========================================================================
   Información tab — Personal/Payment form layout + action row
   =========================================================================== */
.cal-portal-personal-form,
.cal-portal-payment-form {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
/* Personal and Payment forms sit side-by-side on desktop, stacked on mobile. */
.cal-portal-informacion-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.25rem;
}
@media (max-width: 720px) {
    .cal-portal-informacion-grid { grid-template-columns: 1fr; }
}

.cal-portal-actions-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 1rem 1.5rem;
    background: var(--cal-off-white);
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-lg);
    box-shadow: var(--cal-shadow-card);
    margin-top: 0.75rem;
    box-sizing: border-box;
}
.cal-portal-link {
    color: var(--cal-charcoal);
    font-weight: 600;
    text-decoration: none;
    transition: color 0.15s ease;
}
.cal-portal-link:hover {
    color: var(--cal-brand-teal);
    text-decoration: underline;
}

/* ===========================================================================
   Login form (wp_login_form) — renders WordPress's stock markup with
   classes login-username / login-password / login-remember / login-submit
   and .input / .button-primary inputs. These styles are scoped under
   `.cal-portal-card form#cal-portal-login-form` so they don't leak onto
   any other WP form using the same class names.
   =========================================================================== */
.cal-portal-card form#cal-portal-login-form,
.cal-portal-card form.login-form {
    margin: 0;
}
.cal-portal-card form#cal-portal-login-form p,
.cal-portal-card form.login-form p {
    margin: 0 0 1rem 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.cal-portal-card form#cal-portal-login-form label,
.cal-portal-card form.login-form label {
    display: block;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--cal-charcoal);
    margin-bottom: 0;
}
.cal-portal-card form#cal-portal-login-form .input,
.cal-portal-card form.login-form .input {
    width: 100%;
    box-sizing: border-box;
    padding: 0.7rem 0.95rem;
    background: var(--cal-off-white);
    border: 1px solid var(--cal-interactive-bdr);
    border-radius: var(--cal-radius-md);
    color: var(--cal-charcoal);
    font-family: var(--cal-font-family);
    font-size: 0.95rem;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.cal-portal-card form#cal-portal-login-form .input:hover,
.cal-portal-card form.login-form .input:hover {
    border-color: rgba(28, 28, 28, 0.55);
}
.cal-portal-card form#cal-portal-login-form .input:focus,
.cal-portal-card form.login-form .input:focus {
    outline: none;
    border-color: var(--cal-brand-teal);
    box-shadow: var(--cal-shadow-focus);
}
.cal-portal-card form#cal-portal-login-form .forgetmenot,
.cal-portal-card form.login-form .forgetmenot {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.88rem;
    color: var(--cal-muted-gray);
    margin: 0 0 1.25rem 0;
    flex-direction: row;
}
.cal-portal-card form#cal-portal-login-form .forgetmenot label,
.cal-portal-card form.login-form .forgetmenot label {
    font-size: 0.88rem;
    font-weight: 500;
    color: var(--cal-muted-gray);
    margin: 0;
    cursor: pointer;
    display: inline;
}
.cal-portal-card form#cal-portal-login-form .forgetmenot input,
.cal-portal-card form.login-form .forgetmenot input {
    width: 1rem;
    height: 1rem;
    accent-color: var(--cal-brand-teal);
    margin: 0;
}
.cal-portal-card form#cal-portal-login-form .submit,
.cal-portal-card form.login-form .submit {
    margin: 0;
}
.cal-portal-card form#cal-portal-login-form input.button-primary,
.cal-portal-card form.login-form input.button-primary {
    width: 100%;
    box-sizing: border-box;
    background-color: var(--cal-charcoal);
    color: var(--cal-off-white);
    font-family: var(--cal-font-family);
    font-size: 0.95rem;
    font-weight: 600;
    padding: 0.7rem 1.5rem;
    border-radius: var(--cal-radius-pill);
    border: 1px solid var(--cal-charcoal);
    cursor: pointer;
    text-decoration: none;
    transition: background-color 0.15s ease, transform 0.05s ease, box-shadow 0.15s ease;
}
.cal-portal-card form#cal-portal-login-form input.button-primary:hover,
.cal-portal-card form.login-form input.button-primary:hover {
    background: #2a2a2a;
    border-color: #2a2a2a;
    color: var(--cal-off-white);
}
.cal-portal-card form#cal-portal-login-form input.button-primary:active,
.cal-portal-card form.login-form input.button-primary:active {
    transform: translateY(1px);
}
.cal-portal-card form#cal-portal-login-form input.button-primary:focus-visible,
.cal-portal-card form.login-form input.button-primary:focus-visible {
    outline: none;
    box-shadow: var(--cal-shadow-focus);
}

/* ===========================================================================
   Materiales tab — brand assets + QR + pre-personalized links + caption
   =========================================================================== */
.cal-portal-materials-grid {
    display: grid;
    grid-template-columns: 1fr 1.4fr;
    gap: 1rem;
    margin-top: 1rem;
}
.cal-portal-materials-grid > .cal-portal-materials-assets,
.cal-portal-materials-grid > .cal-portal-materials-banner { grid-column: 1 / -1; }
@media (max-width: 900px) {
    .cal-portal-materials-grid { grid-template-columns: 1fr; }
}

/* --- Brand assets grid (5 tiles, full-width row) --- */
.cal-portal-materials-assets-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 0.85rem;
    margin-top: 0.75rem;
}
.cal-portal-materials-asset {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.75rem;
    background-color: #fcfbf8;
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-md);
}
.cal-portal-materials-asset-thumb {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 4 / 3;
    background-color: #fff;
    border: 1px solid var(--cal-light-cream);
    border-radius: 6px;
    overflow: hidden;
}
.cal-portal-materials-asset-thumb img {
    max-width: 100%;
    max-height: 100%;
    display: block;
    object-fit: contain;
}
.cal-portal-materials-asset-meta {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-height: 2.6em;
}
.cal-portal-materials-asset-name {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--cal-charcoal);
    line-height: 1.2;
}
.cal-portal-materials-asset-hint {
    font-size: 0.72rem;
    color: var(--cal-muted-gray);
    line-height: 1.3;
}
.cal-portal-materials-asset-download {
    text-align: center;
    text-decoration: none;
    margin-top: auto;
}
.cal-portal-materials-asset--missing .cal-portal-materials-asset-thumb {
    background-color: #f1ede5;
    border-style: dashed;
}
.cal-portal-materials-asset--missing .cal-portal-materials-asset-thumb::before {
    content: "Imagen no disponible";
    font-size: 0.75rem;
    color: var(--cal-muted-gray);
    text-align: center;
    padding: 0 0.5rem;
}
.cal-portal-materials-assets-note {
    margin: 0.85rem 0 0;
    font-size: 0.78rem;
    color: var(--cal-muted-gray);
    line-height: 1.4;
}
@media (max-width: 900px) {
    .cal-portal-materials-assets-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
}
@media (max-width: 640px) {
    .cal-portal-materials-assets-grid { grid-template-columns: repeat(2, 1fr); }
}
.cal-portal-materials-qr-wrap {
    display: flex;
    justify-content: center;
    padding: 1rem;
    background-color: #fcfbf8;
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-md);
    margin: 0.5rem 0 1rem;
}
.cal-portal-materials-qr-wrap img {
    width: 220px;
    height: 220px;
    display: block;
}
.cal-portal-materials-list {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    margin-top: 0.5rem;
}
.cal-portal-materials-row {
    display: grid;
    grid-template-columns: 36px 1fr auto;
    gap: 0.75rem;
    align-items: center;
    padding: 0.6rem 0.75rem;
    background-color: #fcfbf8;
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-md);
}
.cal-portal-materials-row-icon {
    width: 32px;
    height: 32px;
    border-radius: 6px;
    background-color: var(--cal-charcoal);
    color: #f7f4ed;
    font-size: 11px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    letter-spacing: 0.02em;
}
.cal-portal-materials-row-label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--cal-charcoal);
    margin-bottom: 0.15rem;
}
.cal-portal-materials-row-input {
    width: 100%;
    font-size: 0.8rem;
    padding: 0.3rem 0.5rem;
    border: 1px solid var(--cal-light-cream);
    border-radius: 4px;
    background-color: #fff;
    color: var(--cal-muted-gray);
    font-family: ui-monospace, SFMono-Regular, monospace;
}
.cal-portal-materials-banner-text {
    width: 100%;
    font-family: inherit;
    font-size: 0.95rem;
    line-height: 1.5;
    padding: 0.75rem 1rem;
    border: 1px solid var(--cal-light-cream);
    border-radius: var(--cal-radius-md);
    background-color: #fcfbf8;
    color: var(--cal-charcoal);
    resize: vertical;
}
.cal-portal-materials-empty {
    margin-top: 1rem;
}

/* ===========================================================================
   Responsive — keep the portal usable from 320px up.
   ---------------------------------------------------------------------------
   Breakpoints:
     900px  — tablet: 2-column grids collapse to 1, header chrome shrinks
     640px  — phone:  cards tighten, affiliate rows stack, tabs scroll
   Anything above 900px keeps the desktop layout untouched.
   =========================================================================== */

/* ---------- Tablet ---------- */
@media (max-width: 900px) {
    .cal-portal-header {
        padding: 1rem 1.25rem;
        gap: 0.75rem;
    }
    .cal-portal-main {
        padding: 2rem 1rem 3rem;
    }
    .cal-portal-footer {
        padding: 1.25rem 1.25rem;
    }
    .cal-portal-card,
    .cal-portal-affiliate-row-wrap,
    .cal-portal-affiliate-block,
    .cal-portal-ventas-month-block {
        padding: 1.25rem 1.25rem;
    }
    /* The Informacion grid already collapses to 1 column at 720px;
       the affiliate link row + value need to stack here so the label
       doesn't squeeze the URL/coupon on a narrow viewport. */
    .cal-portal-affiliate-row {
        align-items: flex-start;
        flex-direction: column;
        gap: 0.5rem;
    }
    .cal-portal-affiliate-label {
        flex: 0 0 auto;
        width: 100%;
    }
    .cal-portal-affiliate-value {
        flex: 1 1 auto;
        width: 100%;
        flex-wrap: wrap;
    }
}

/* ---------- Phone ---------- */
@media (max-width: 640px) {
    /* Header: stack the brand over the nav so they never compete for
       horizontal space. Nav shrinks its padding so three items fit
       even on a 320px-wide viewport. */
    .cal-portal-header {
        flex-direction: column;
        align-items: stretch;
        width: 100%;
        padding: 0.85rem 0.9rem;
        gap: 0.5rem;
    }
    .cal-portal-brand {
        align-self: center;
    }
    .cal-portal-logo {
        max-height: 52px;
    }
    .cal-portal-nav {
        width: 100%;
        justify-content: space-between;
        gap: 0.5rem;
        flex-wrap: wrap;
    }
    .cal-portal-nav-link {
        font-size: 0.88rem;
        padding: 0.35rem 0.65rem;
    }
    .cal-portal-nav-user {
        flex: 1 1 100%;
        text-align: center;
        font-size: 0.82rem;
    }

    /* Main + cards */
    .cal-portal-main {
        padding: 1.25rem 0.9rem 2.5rem;
    }
    .cal-portal-card,
    .cal-portal-affiliate-row-wrap,
    .cal-portal-affiliate-block,
    .cal-portal-ventas-month-block {
        padding: 1rem 0.95rem;
        border-radius: var(--cal-radius-md);
    }
    .cal-portal-h1 {
        font-size: clamp(1.4rem, 6vw, 1.75rem);
    }
    .cal-portal-section-title,
    .cal-portal-card-title {
        font-size: 1.05rem;
    }

    /* Form controls: tap targets stay ≥44px tall, full width so the
       field doesn't try to fit beside the label. */
    .cal-portal-form-field input,
    .cal-portal-form-field select,
    .cal-portal-form-field textarea,
    .cal-portal-form-input,
    .cal-portal-form-select,
    .cal-portal-form-textarea {
        font-size: 16px; /* avoid iOS zoom-on-focus */
        min-height: 44px;
        padding: 0.65rem 0.85rem;
    }
    .cal-portal-form-field textarea,
    .cal-portal-form-textarea {
        min-height: 96px;
    }
    .cal-portal-button {
        min-height: 44px;
    }

    /* Tab nav: keep the pill design but let it wrap so two pills fit
       per line on narrow phones, and shrink horizontal padding so the
       active tab doesn't overflow. */
    .cal-portal-tabs {
        align-self: stretch;
        justify-content: center;
        flex-wrap: wrap;
        gap: 0.35rem;
        padding: 0.35rem;
    }
    .cal-portal-tab-link {
        padding: 0.45rem 0.95rem;
        font-size: 0.85rem;
    }

    /* Ventas tiles: 5-column summary already collapses at 1100px; on
       phones the 3-column tiles also stack so each tile reads at full
       width. The earlier @media (max-width: 640px) rule already does
       this for the 3-column variant; the explicit one-column for the
       5-column is also at 640px — both stack together here. */

    /* Ventas month tables: turn them into horizontally-scrollable
       blocks so wide columns (order ID, totals) stay legible without
       shrinking past readability. Sticky first column keeps the row
       label visible while scrolling horizontally. */
    .cal-portal-table {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        font-size: 0.85rem;
    }
    .cal-portal-table th,
    .cal-portal-table td {
        padding: 0.55rem 0.7rem;
        white-space: nowrap;
    }
    .cal-portal-table th:first-child,
    .cal-portal-table td:first-child {
        position: sticky;
        left: 0;
        background: var(--cal-cream);
        z-index: 1;
    }
    .cal-portal-table th:first-child {
        background: var(--cal-light-cream);
    }

    /* Materials row: collapse the 3-column grid (icon / label+input /
       action) to a single column so the long affiliate URLs don't
       truncate on small screens. */
    .cal-portal-materials-row {
        grid-template-columns: 32px 1fr;
        grid-template-rows: auto auto;
        row-gap: 0.4rem;
    }
    .cal-portal-materials-row > .cal-portal-button {
        grid-column: 1 / -1;
        justify-self: stretch;
    }

    /* Modal: full-bleed with thin margins instead of centred 33rem
       panel — much friendlier on a phone. */
    .cal-portal-modal {
        padding: 0.5rem;
    }
    .cal-portal-modal__panel {
        width: 100%;
        max-width: none;
        padding: 0.85rem 0.95rem;
        max-height: calc(100vh - 1rem);
    }
    .cal-portal-modal__cta {
        min-width: 0;
        width: 100%;
    }

    /* Footer */
    .cal-portal-footer {
        padding: 1rem 0.9rem;
        font-size: 0.8rem;
    }
}
