/* ============================================================================
   LAYOUT — the app shell: sidebar, topbar, scroll column, page rhythm.

   Shell class names (.app, .portal-sidebar, .content-wrapper, .portal-topbar,
   body.portal-drawer-open) are NOT free to rename: portal-sidebar.js,
   configuration-section-nav.js, portal-tour.js and the E2E suite all resolve
   them. This layer restyles that markup completely while keeping the hooks.
   ========================================================================= */

/* The shell owns the viewport; the content column is the only scroller. */
.app {
    display: grid;
    grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
}

/* ------------------------------------------------------------------ SIDEBAR
   A quiet, recessive rail. It is on screen every second the owner uses the
   portal, so it is the last thing that should compete for attention: one
   surface step down from the page, a hairline edge, and no fills except on
   the single active item. */
.portal-sidebar {
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: var(--surface);
    border-right: 1px solid var(--border);
    overflow-y: auto;
}

.portal-sidebar__brand {
    display: flex;
    align-items: center;
    /* Matches --topbar-height so the brand row and the page title sit on one
       optical line across the fold. */
    height: var(--topbar-height);
    flex: 0 0 auto;
    padding: 0 var(--space-4);
    border-bottom: 1px solid var(--border);
}

.portal-sidebar__brand-link {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: var(--weight-bold);
    letter-spacing: -0.01em;
    color: var(--text);
}

.portal-sidebar__brand-link:hover {
    color: var(--text);
    text-decoration: none;
}

.portal-sidebar__brand-icon {
    display: inline-flex;
    color: var(--accent-text);
}

/* -------------------------------------------------------------- SIDEBAR NAV */
.portal-nav {
    flex: 1 1 auto;
    min-height: 0;
    padding: var(--space-4) var(--space-3);
    overflow-y: auto;
}

/* The shop name / "Your shops" label. An eyebrow, not a heading: it names the
   scope of the links below rather than titling a section. */
.portal-nav__heading {
    margin: 0 0 var(--space-3);
    padding: 0 var(--space-2);
    font-family: var(--font-display);
    font-size: var(--text-md);
    font-weight: var(--weight-semibold);
    color: var(--text);
    /* Long shop names must not blow out the fixed rail width. */
    overflow-wrap: anywhere;
}

a.portal-nav__heading--link {
    display: block;
    color: var(--accent-text);
}

.portal-nav__empty,
.portal-nav__role {
    margin: 0 0 var(--space-3);
    padding: 0 var(--space-2);
    font-size: var(--text-xs);
    color: var(--text-muted);
}

.portal-nav__role {
    display: inline-block;
    padding: var(--space-05) var(--space-2);
    margin-left: var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--surface-2);
    /* Genuinely secondary: this pill annotates the shop heading with the viewer's
       role. It ranks below the nav links it sits among, and its sibling
       .portal-nav__empty is muted for the same reason. */
    color: var(--text-muted);
    font-size: var(--text-micro);
    font-weight: var(--weight-medium);
}

.portal-subnav {
    display: flex;
    flex-direction: column;
    gap: var(--space-05);
}

.portal-nav-link,
.portal-sidebar__account-link,
.portal-sidebar__tour-btn,
.portal-sidebar__signout-btn {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-2) var(--space-2);
    border: 0;
    border-radius: var(--radius-md);
    background: none;
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--text);
    text-align: left;
    cursor: pointer;
    transition: background-color var(--motion-fast) var(--ease-out),
                color var(--motion-fast) var(--ease-out);
}

.portal-nav-link:hover,
.portal-sidebar__account-link:hover,
.portal-sidebar__tour-btn:hover,
.portal-sidebar__signout-btn:hover {
    background: var(--surface-2);
    color: var(--text);
    text-decoration: none;
}

/* The active item is the only filled thing in the rail. Accent tint plus an
   accent-coloured label and icon — no left bar, which would need a second
   alignment rule for every nesting level. */
.portal-nav-link.active,
.portal-sidebar__account-link.active {
    background: var(--accent-tint);
    /* --accent-on-tint, not --accent-text: the ink sits on the tint, not on the
       rail's own surface, and --accent-text measures 4.33:1 there in dark. */
    color: var(--accent-on-tint);
    font-weight: var(--weight-semibold);
}

.portal-nav-link__icon {
    display: inline-flex;
    flex: 0 0 auto;
    /* Icons inherit the link colour so the active state needs no icon rule. */
    color: currentColor;
    opacity: 0.75;
}

.portal-nav-link.active .portal-nav-link__icon,
.portal-sidebar__account-link.active .portal-nav-link__icon {
    opacity: 1;
}

/* Legible-off LOCKED nav entry (#572, ADR 0032): an owner without the knowledge_usage
   entitlement still SEES the Knowledge item (visible, not hidden), muted with a trailing
   lock glyph, and it links to the page's upsell. Muted uses --text-muted, the AA-legal
   muted ink — never lighter (#525). Hover still lifts it, so it reads as reachable. */
.portal-nav-link--locked {
    color: var(--text-muted);
}

.portal-nav-link--locked .portal-nav-link__icon {
    opacity: 0.6;
}

.portal-nav-link__lock {
    display: inline-flex;
    flex: 0 0 auto;
    margin-left: auto;
    color: currentColor;
    opacity: 0.75;
}

.portal-sidebar__tour-btn {
    margin-top: var(--space-4);
    color: var(--text-muted);
}

/* ----------------------------------------------------------- SHOP SWITCHER */
.portal-shop-switcher-field {
    margin-bottom: var(--space-4);
    padding: 0 var(--space-2);
}

.portal-shop-switcher__label {
    display: block;
    margin-bottom: var(--space-1);
    font-size: var(--text-micro);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--text-muted);
}

.portal-shop-switcher {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg);
    font-size: var(--text-sm);
    color: var(--text);
}

/* --------------------------------------------------------- SIDEBAR FOOTER */
.portal-sidebar__footer {
    flex: 0 0 auto;
    padding: var(--space-3);
    border-top: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: var(--space-05);
}

.portal-sidebar__signout {
    margin: 0;
}

.portal-sidebar__signout-btn {
    color: var(--text-muted);
}

.portal-sidebar__account-info {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.portal-sidebar__account-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.portal-sidebar__account-email {
    font-size: var(--text-xs);
    font-weight: var(--weight-normal);
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ------------------------------------------------------------ CONTENT COLUMN
   .content-wrapper is the sole scroll container — configuration-section-nav.js
   binds its scroll listener here because window scroll never fires in this
   shell. Do not move the overflow to another element. */
.content-wrapper {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    overflow-y: auto;
    /* Keep the sticky topbar and drawer stable at scroll boundaries (#347). */
    overscroll-behavior: contain;
}

.portal-topbar {
    position: sticky;
    top: 0;
    z-index: var(--z-topbar);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex: 0 0 auto;
    height: var(--topbar-height);
    padding: 0 var(--space-6);
    background: var(--bg);
    border-bottom: 1px solid var(--border);
}

.portal-topbar__title {
    font-family: var(--font-display);
    font-size: var(--text-md);
    font-weight: var(--weight-semibold);
    letter-spacing: normal;
    color: var(--text);
}

.portal-topbar__theme {
    margin-left: auto;
}

/* Drawer toggle: hidden on desktop, where the rail is always present. */
.portal-topbar__toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
}

.portal-topbar__toggle:hover {
    background: var(--surface-2);
}

/* ----------------------------------------------------------------- MAIN
   The page rhythm. Sections are separated by --space-8; the main area fills
   the viewport minus the sidebar. Readability is the GRID's job — a card
   claims the span its content needs — not a global cap. */
.portal-main {
    flex: 1 1 auto;
    width: 100%;
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
}

/* ================================================================== GRID
   12 columns across the full main area. A card claims the span its CONTENT
   needs — that is the whole fix. Fields still fill their cell.

   TWO levels: .page-grid sizes cards across the page, .field-grid sizes
   fields inside a card. Both are 12-column so the same fractional reasoning
   applies, but they do not share breakpoints — the outer grid reflows when
   the page is narrow, the inner grid reflows when the CARD is narrow.

   BREAKPOINTS — both are content breakpoints, independent of the shell:
     1200px  the main area (viewport minus sidebar) drops below ~956px; at
             that width a col-5 card is ~398px, which is the narrowest a
             card with a field-grid should go. Wider spans (5–9) stack to
             full width; 3- and 4-col cards pair at half width.
      760px  even half-width cards are too narrow; everything stacks.
   Neither coincides with the 860px shell breakpoint (sidebar → drawer) or
   the 640px onboarding breakpoint — if a future breakpoint needs to match
   one of those, say so, because a later reader will assume they are coupled. */
.page-grid {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--space-5);
}

.col-3  { grid-column: span 3; }
.col-4  { grid-column: span 4; }
.col-5  { grid-column: span 5; }
.col-6  { grid-column: span 6; }
.col-7  { grid-column: span 7; }
.col-8  { grid-column: span 8; }
.col-9  { grid-column: span 9; }
.col-12 { grid-column: span 12; }

@media (max-width: 1200px) {
    .col-3 { grid-column: span 6; }
    .col-4 { grid-column: span 6; }
    .col-5,
    .col-7,
    .col-8,
    .col-9 { grid-column: span 12; }
}
@media (max-width: 760px) {
    .col-3,
    .col-4,
    .col-6 { grid-column: span 12; }
}

/* The field grid sizes cells INSIDE a card. Fields keep width:100% and fill
   their cell — there is no per-field max-width anywhere. */
.field-grid {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--space-4);
}

.fcol-3  { grid-column: span 3; }
.fcol-4  { grid-column: span 4; }
.fcol-6  { grid-column: span 6; }
.fcol-12 { grid-column: span 12; }

@media (max-width: 760px) {
    .fcol-3,
    .fcol-4,
    .fcol-6 { grid-column: span 12; }
}

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

/* --------------------------------------------------------------- SCRIM
   Only ever visible behind the mobile drawer. */
.portal-scrim {
    display: none;
    position: fixed;
    inset: 0;
    z-index: var(--z-scrim);
    background: rgba(2, 24, 36, 0.5);
}

/* ============================================================== AUTH SHELL
   The OTHER shell in this unit (_AuthLayout): one centered card, no sidebar,
   no topbar. It is a shell rather than a page style because five unauthenticated
   pages plus the invite-acceptance flow share it.

   It is deliberately narrow. Every page it carries is a single short form or a
   single sentence of outcome, and a login box that spans a 27" monitor reads as
   an application form. --measure is the prose cap and is far too wide here, so
   the card gets its own bound. */
.auth-body {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg);
}

.auth-shell {
    width: 100%;
    max-width: 26rem;
    padding: var(--space-8) var(--space-5);
}

/* A panel by the .panel definition — a bounded thing you act on — but it cannot
   reuse .panel: this one floats on an empty page rather than sitting in a
   content column, so it is the rare case that earns a shadow under the
   elevation rule (nothing else is on the page for a border to separate it from). */
.auth-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-8);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: var(--shadow-raised);
}

/* Brand on the leading edge, theme toggle on the trailing one — the same
   arrangement as the app shell's topbar, so the two shells feel related. */
.auth-card__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-2);
}

/* The wordmark is set as an eyebrow, not a heading: it identifies the product,
   while the page's own h1 says what you are here to do. Ranking it below the h1
   is the point — on a login page the h1 is "Log in", not "Sailesman". */
.auth-brand {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-display);
    font-size: var(--text-xs);
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--text);
}

.auth-brand__icon {
    display: inline-flex;
    color: var(--accent-text);
}

/* The cross-link to the opposite flow ("no account yet?"). Sits below the form,
   demoted, because it is the path you did NOT come here for. */
.auth-alt {
    margin: 0;
    font-size: var(--text-xs);
    color: var(--text-muted);
}

/* ================================================================== MOBILE
   860px is a FROZEN CONTRACT with portal-sidebar.js, which reads the same
   breakpoint from matchMedia("(max-width: 860px)") to decide whether the
   sidebar is inert. Drift here and the drawer is either focus-trapped while
   visible or reachable by Tab while off-screen. Change both or neither. */
@media (max-width: 860px) {
    .app {
        grid-template-columns: minmax(0, 1fr);
    }

    .portal-sidebar {
        position: fixed;
        inset: 0 auto 0 0;
        z-index: var(--z-sidebar);
        width: min(var(--sidebar-width), 86vw);
        box-shadow: var(--shadow-overlay);
        transform: translateX(-100%);
        transition: transform var(--motion-base) var(--ease-out);
    }

    body.portal-drawer-open .portal-sidebar {
        transform: translateX(0);
    }

    body.portal-drawer-open .portal-scrim {
        display: block;
    }

    /* Belt-and-braces while the drawer is modal. .app is height:100dvh with
       overflow:hidden, so the body does not scroll and this is a no-op in a
       stable viewport — it is here for the case that viewport unit is not
       stable, i.e. mobile Safari collapsing its chrome mid-gesture, where the
       body can briefly exceed the frame and scroll behind the open drawer. */
    body.portal-drawer-open {
        overflow: hidden;
    }

    .portal-topbar__toggle {
        display: inline-flex;
    }

    .portal-topbar {
        padding: 0 var(--space-4);
    }

    .portal-main {
        gap: var(--space-6);
    }
}
