/*
 * Builder chrome — toolbar + canvas around the resume "paper".
 * Template appearance itself lives in css/templates/{id}.css.
 */

.builder {
    min-height: calc(100vh - 60px);
    background: var(--gray-200);
}

/* Edit-mode-only page-break guide (JS-injected, see builder.js
   renderPageBreakLines) — .resume-page needs a positioning context for the
   absolutely-positioned lines; this never reaches mPDF, which renders the
   template file standalone and never loads builder.css. */
.builder__canvas .resume-page {
    position: relative;
}
.builder__page-break-line {
    position: absolute;
    left: 0;
    right: 0;
    height: 0;
    border-top: 1px dashed var(--color-warn);
    pointer-events: none;
    z-index: 4;
}

/* ---- sample-content notice --------------------------------------------- */
.builder__sample-notice {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-3);
    padding: var(--sp-2) var(--sp-4);
    background: var(--color-info-bg);
    color: var(--color-info-text);
    font-size: var(--fs-sm);
    text-align: center;
}
.builder__sample-notice-close {
    border: 0;
    background: transparent;
    color: inherit;
    font-size: var(--fs-lg);
    line-height: 1;
    cursor: pointer;
    padding: 0;
}

/* ---- overflow warning (non-multipage template running past one page) --- */
.builder__overflow-warning {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-4);
    background: var(--color-warn-bg);
    color: var(--color-warn-text);
    font-size: var(--fs-sm);
    text-align: center;
}
.builder__overflow-warning a {
    color: inherit;
    font-weight: 600;
    text-decoration: underline;
    white-space: nowrap;
}

/* ---- toolbar --------------------------------------------------------- */
.builder__toolbar {
    position: sticky;
    top: 0;
    z-index: 20;
    background: var(--color-bg);
    border-bottom: 1px solid var(--color-border);
    padding: var(--sp-2) var(--sp-4);
}
.builder__toolbar::after {
    content: "";
    display: table;
    clear: both;
}
.builder__toolbar-left {
    float: left;
}
.builder__toolbar-right {
    float: right;
    text-align: right;
    padding-top: 3px;
}
.builder__title {
    font-size: var(--fs-sm);
    font-weight: 600;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: var(--sp-1) var(--sp-2);
    width: 260px;
    max-width: min(50vw, 100%);
}
.builder__title:hover {
    border-color: var(--color-border);
}
.builder__title:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}
/* Subtle "N pages" note next to the template switcher (multipage templates only). */
.builder__page-note {
    display: inline-block;
    margin-left: var(--sp-2);
    font-size: var(--fs-xs);
    color: var(--gray-500);
    vertical-align: middle;
}

.builder__photo {
    display: inline-block;
    margin-left: var(--sp-3);
    vertical-align: middle;
}
.builder__photo-btn,
.builder__photo-remove {
    font-family: inherit;
    font-size: var(--fs-xs);
    color: var(--gray-600);
    background: var(--gray-100);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--sp-1) var(--sp-2);
    cursor: pointer;
}
.builder__photo-btn:hover,
.builder__photo-remove:hover {
    background: var(--gray-200);
}
.builder__photo-remove {
    margin-left: var(--sp-1);
    color: var(--color-error-text);
}
.builder__photo-hint {
    display: block;
    margin-top: var(--sp-1);
    font-size: 0.6875rem;
    color: var(--gray-500);
    max-width: 220px;
}
.builder__photo-error {
    display: block;
    margin-top: var(--sp-1);
    font-size: 0.6875rem;
    color: var(--color-error-text);
    max-width: 220px;
}

/* Wrapper around the switcher + photo controls. `inline` on desktop so its
   inline-block children lay out in the toolbar exactly as they did before the
   wrapper existed; it becomes a collapsible panel under 768px. */
.builder__toolbar-more {
    display: inline;
}
.builder__more-btn {
    display: none;         /* mobile-only disclosure */
}

.builder__status {
    display: inline-block;
    font-size: var(--fs-xs);
    margin-right: var(--sp-3);
    vertical-align: middle;
    min-width: 60px;
}
.builder__status--saving { color: var(--color-warn-text); }
.builder__status--saved  { color: var(--color-success-text); }
.builder__status--error  { color: var(--color-error-text); }

.builder__download {
    vertical-align: middle;
}

.builder__ats {
    display: inline-block;
    position: relative;
    margin-right: var(--sp-3);
    vertical-align: middle;
}
.builder__ats-badge {
    font-family: inherit;
    font-size: var(--fs-xs);
    font-weight: 600;
    border: 1px solid transparent;
    border-radius: 999px;
    padding: var(--sp-1) var(--sp-3);
    cursor: pointer;
}
.builder__ats-badge--bad  { background: var(--color-error-bg); color: var(--color-error-text); }
.builder__ats-badge--warn { background: var(--color-warn-bg); color: var(--color-warn-text); }
.builder__ats-badge--good { background: var(--color-success-bg); color: var(--color-success-text); }

.builder__ats-panel {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: var(--sp-2);
    width: 18.75rem;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    z-index: 30;
    text-align: left;
}
.builder__ats-checks {
    list-style: none;
    margin: 0;
    padding: var(--sp-2) 0;
    max-height: 20rem;
    overflow-y: auto;
}
.builder__ats-check {
    padding: var(--sp-2) var(--sp-4);
    border-left: 3px solid transparent;
    font-size: var(--fs-xs);
}
.builder__ats-check--pass { border-left-color: var(--color-success); }
.builder__ats-check--warn { border-left-color: var(--color-warn); }
.builder__ats-check--fail { border-left-color: var(--color-error); }
.builder__ats-check--skipped { border-left-color: var(--gray-400); }
.builder__ats-check-label {
    display: block;
    font-weight: 600;
    color: var(--gray-800);
}
.builder__ats-check-message {
    display: block;
    color: var(--gray-600);
    margin-top: 2px;
}
.builder__ats-panel-footer {
    display: block;
    padding: var(--sp-3) var(--sp-4);
    border-top: 1px solid var(--color-border);
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--color-primary);
    text-decoration: none;
}
.builder__ats-panel-footer:hover {
    text-decoration: underline;
}

/* ---- canvas ---------------------------------------------------------- */
.builder__canvas {
    padding: var(--sp-8) var(--sp-4) var(--sp-16);
    text-align: center;            /* centers the inline-block paper */
}
.builder__canvas .resume-page {
    display: inline-block;
    text-align: left;
    box-shadow: var(--shadow-md);
    vertical-align: top;
}

/* Transform target for the mobile "Aperçu" view — a no-op wrapper otherwise.
   The scale factor, width and compensating negative margin are all set inline
   by builder.js (applyCanvasScale), which is also what keeps the template CSS
   untouched: nothing here reaches inside .resume-page's own styling. */
.builder__scaler {
    display: inline-block;
    vertical-align: top;
    text-align: left;
}

/* Touch devices at any width — landscape phones and tablets, which match none
   of the max-width: 768px rules below. Sizing only; the two-view switcher and
   the collapsed toolbar stay width-based, because at 844px landscape the paper
   fits without scaling and the desktop toolbar has room. See the matching block
   in main.css (MOBILE-AUDIT.md backlog item 9). */
@media (hover: none) and (pointer: coarse) {
    .builder__title,
    .builder__photo-btn,
    .builder__photo-remove,
    .builder__ats-badge,
    .builder__more-btn,
    .builder__viewbtn {
        min-height: 2.75rem;
    }
    .builder__title {
        font-size: 1rem;   /* <16px auto-zooms on iOS focus, in either orientation */
    }
    .builder__sample-notice-close {
        min-width: 2.75rem;
        min-height: 2.75rem;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        flex: 0 0 auto;
    }
}

/* Off-screen copy of the template rendered in pdf mode, which builder.js
   measures for the page count (see .builder__measure in views/pages/builder.php
   and App\Services\TemplateRenderer).

   `visibility: hidden` and NOT `display: none`: the element must still be laid
   out or offsetHeight is 0. Pushed off-canvas rather than merely hidden so it
   can never be reached by a pointer, and given the same 794px paper width the
   template CSS assumes. `left` (not a transform) because a transform would
   scale/round the measured height. It sits outside .builder__canvas on
   purpose, so the canvas's own `.resume-page { display:inline-block;
   position:relative }` rules never apply to it. */
.builder__measure {
    position: absolute;
    top: 0;
    left: -10000px;
    width: 794px;
    visibility: hidden;
    pointer-events: none;
}

/* The measuring container must be laid out with the SAME cascade mPDF sees,
   and mPDF loads only the template stylesheet — never main.css. main.css
   declares bare `h1 { line-height: 1.2 }` and `h2 { line-height: 1.3 }`, which
   reach every .cv-section-title (an <h2>) in here and render it at 18.2px
   where the template's own inherited line-height gives 21px. That is 2.81px
   short PER HEADING: the editor measured a document ~13-17px shorter than the
   one it exports, and templates whose sample lands within that of the page-1
   capacity reported one page while the export ran to two (measured on pulse
   +2px headroom, couture +0, ambre +11 — all three flip to the correct count
   with this rule in place).

   `:where()` keeps this at specificity (0,0,1) on purpose: identical to
   main.css's bare `h2`, so it wins on source order (builder.css is linked
   from views/pages/builder.php, after main.css in views/partials/head.php),
   while ANY template rule that sets a heading's line-height with a class
   still beats it — which is what keeps this a leak guard rather than an
   override of template design.

   Scoped to the measuring container only. The visible canvas inherits the
   same main.css rules and so still paints headings 2.81px tighter than the
   export; that is a separate, cosmetic WYSIWYG drift, deliberately left
   alone here so this change cannot move a single visible pixel. */
:where(.builder__measure) h1,
:where(.builder__measure) h2,
:where(.builder__measure) h3,
:where(.builder__measure) h4,
:where(.builder__measure) h5,
:where(.builder__measure) h6 {
    line-height: inherit;
}

/* Fallback path only. builder.js measures .builder__measure when it is
   present; if the pdf-mode markup is unavailable it falls back to measuring
   the edit canvas, and then the "+ Add …" buttons — which sit in normal flow,
   unlike the absolutely-positioned .edit-controls — must not count toward the
   mPDF page boundary. Applies at every width: the page count must not depend
   on viewport or on which mobile view is active. */
.builder--measuring .cv-add {
    display: none !important;
}

/* ---- view switcher (mobile only) ------------------------------------- */
.builder__viewbar {
    display: none;
}

/* ---- mobile chrome ----------------------------------------------------
 * Two surfaces under 768px:
 *   "Éditer"  — the paper at 1:1, panned horizontally inside the canvas, so
 *               contenteditable text stays legible and tappable.
 *   "Aperçu"  — the paper transform-scaled to viewport width (builder.js
 *               applyCanvasScale) with edit-only chrome hidden, so a whole
 *               page reads like the export.
 * The transform lives on .builder__scaler; template CSS is never touched, and
 * builder.js measures with offsetHeight/offsetTop so the page model can't be
 * corrupted by the scale (MOBILE-AUDIT.md, session 3).
 */
@media (max-width: 768px) {
    /* One wrapping flex context for the whole toolbar: `display: contents` on
       the two float wrappers promotes their children to items of .builder__toolbar
       itself, so the title can take a full row while the disclosure, ATS badge and
       status share the next one. Kept as two rows (~110px) instead of the three
       the nested-flex version produced, and well under the 238px the audit
       measured for the original stacked layout. */
    .builder__toolbar {
        padding: var(--sp-2) var(--sp-4);
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: var(--sp-2);
        text-align: left;
    }
    .builder__toolbar::after {
        display: none;   /* float clearfix; a flex container would make it an item */
    }
    .builder__toolbar-left,
    .builder__toolbar-right {
        display: contents;
    }
    .builder__title {
        flex: 1 0 100%;
        width: 100%;
        max-width: 100%;
        font-size: 1rem;   /* <16px auto-zooms on iOS focus */
        height: 2.75rem;
    }
    .builder__toolbar-more {
        order: 1;          /* full-width panel drops below the row it opens from */
    }
    .builder__photo {
        margin-left: 0;
    }
    .builder__photo-btn,
    .builder__photo-remove,
    .builder__ats-badge {
        min-height: 2.75rem;
    }
    .builder__photo-hint,
    .builder__photo-error {
        max-width: 100%;
    }
    .builder__ats { margin-right: 0; }
    .builder__ats-panel {
        width: min(18.75rem, calc(100vw - var(--sp-8)));
    }
    .builder__status { margin-right: 0; }

    /* Same 20x20 close-button bug session 1 fixed on the FR-suggestion banner —
       this one was missed because the builder was out of scope then. Found by
       scripts/mobile-probe.mjs. */
    .builder__sample-notice-close {
        min-width: 2.75rem;
        min-height: 2.75rem;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        flex: 0 0 auto;
    }

    /* Toolbar collapses to two rows: title, then the disclosure + ATS + status.
       Download moves to the always-visible bottom bar, so it isn't duplicated
       here. This is what takes the stacked toolbar off its measured 238px. */
    .builder__more-btn {
        display: inline-flex;
        align-items: center;
        gap: var(--sp-1);
        min-height: 2.75rem;
        font-family: inherit;
        font-size: var(--fs-xs);
        color: var(--gray-600);
        background: var(--gray-100);
        border: 1px solid var(--color-border);
        border-radius: var(--radius-sm);
        padding: var(--sp-1) var(--sp-3);
        cursor: pointer;
    }
    .builder__toolbar-more {
        display: none;
        flex: 1 0 100%;
    }
    .builder--more-open .builder__toolbar-more {
        display: flex;
        flex-wrap: wrap;
        align-items: flex-start;
        gap: var(--sp-2);
        padding-top: var(--sp-2);
        border-top: 1px solid var(--color-border);
    }
    .builder--more-open .builder__more-btn {
        background: var(--gray-200);
    }
    .builder__download {
        display: none;   /* lives in .builder__viewbar on mobile */
    }

    /* -- canvas: shared -- */
    .builder__canvas {
        padding: var(--sp-5) var(--sp-2) var(--sp-10);
        text-align: left;
    }

    /* -- "Éditer": 1:1, pan horizontally. overflow-x on the canvas is what
          keeps the 794px paper from pushing the whole document wide (the
          audit's documentElement.scrollWidth == viewport criterion). -- */
    .builder[data-mobile-view="edit"] .builder__canvas {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-x: contain;
    }

    /* -- "Aperçu": scaled. overflow clips the untransformed 794px layout box;
          the scaler's negative margin-bottom (set in JS) already collapses the
          reserved vertical space, so nothing is cut off. -- */
    .builder--scaled .builder__canvas {
        overflow: hidden;
        padding-left: 0;
        padding-right: 0;
    }
    .builder--scaled .builder__scaler {
        display: block;
    }
    /* Kills the inline-block line box so the scaler's offsetHeight is exactly
       the paper height — the negative margin is derived from it. */
    .builder--scaled .builder__canvas .resume-page {
        display: block;
    }
    /* Edit-only chrome off in preview. .cv-add sits in normal flow, so hiding it
       changes the measured height — builder.js re-runs updatePageCount on every
       view switch for exactly this reason. */
    .builder[data-mobile-view="preview"] .cv-add,
    .builder[data-mobile-view="preview"] .edit-controls {
        display: none !important;
    }

    /* -- sticky bottom view bar -- */
    .builder__viewbar {
        display: flex;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 30;
        align-items: center;
        gap: var(--sp-2);
        padding: var(--sp-2) var(--sp-3);
        padding-bottom: calc(var(--sp-2) + env(safe-area-inset-bottom, 0px));
        background: var(--color-bg);
        border-top: 1px solid var(--color-border);
        box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.08);
    }
    .builder__viewbtn {
        flex: 1 1 0;
        min-width: 0;
        min-height: 2.75rem;
        font-family: inherit;
        font-size: 1rem;
        color: var(--gray-700);
        background: var(--gray-100);
        border: 1px solid var(--color-border);
        border-radius: var(--radius-sm);
        padding: var(--sp-1) var(--sp-2);
        cursor: pointer;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .builder__viewbtn.is-active {
        background: var(--color-primary);
        border-color: var(--color-primary);
        color: #fff;
        font-weight: 600;
    }
    .builder__viewbar-status {
        flex: 0 0 auto;
        font-size: var(--fs-xs);
    }
    .builder__viewbar-download {
        flex: 0 0 auto;
        min-height: 2.75rem;
        white-space: nowrap;
    }
    /* Clear the fixed bar so it never covers the last of the page content —
       including the copy section and footer that sit after .builder. Safe to
       scope to body: builder.css is only ever loaded on the builder page. */
    body {
        padding-bottom: calc(3.75rem + env(safe-area-inset-bottom, 0px));
    }
}

/* ---------------------------------------------------------------------------
   Template slider — the builder's template switcher (views/partials/template-slider.php).
   Replaced the .builder__template-switcher dropdown. A full-width strip of its
   own below the toolbar, so it stays visible on mobile instead of collapsing
   behind the "Options" disclosure.

   No flex/grid restriction applies here: this is builder chrome, never emitted
   into a resume template, so it never reaches mPDF.
   --------------------------------------------------------------------------- */
.tpl-slider {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--sp-1);
    padding: var(--sp-2) var(--sp-3);
    background: var(--color-bg);
    border-bottom: 1px solid var(--color-border);
}

.tpl-slider__strip {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    gap: var(--sp-2);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;   /* native momentum scrolling on iOS */
    scrollbar-width: none;               /* prev/next chevrons already provide desktop
                                             navigation, so the scrollbar is hidden on
                                             every pointer type, not just touch, rather
                                             than showing a chunky horizontal bar under
                                             the thumbnails */
    flex: 1 1 auto;
    min-width: 0;                        /* lets the flex child actually shrink */
}
.tpl-slider__strip::-webkit-scrollbar { display: none; }

.tpl-slider__item {
    flex: 0 0 auto;
    /* center, not start: the strip centres the active template on load, and a
       `start` snap point sits ~half a strip away from that, so proximity
       snapping dragged the card off-centre the moment it was placed. With
       `center` the snap point and the load position are the same place. */
    scroll-snap-align: center;
}

/* Hidden by the multipage filter (the overflow warning's "Try a multipage
   template" link). display:none keeps it out of the tab order too. */
.tpl-slider__item[hidden] { display: none; }

.tpl-slider__card {
    display: block;
    width: 92px;
    padding: 3px;
    border: 2px solid transparent;
    border-radius: var(--radius-sm);
    text-decoration: none;
    color: var(--gray-700);
    background: none;
}
.tpl-slider__card:hover  { background: var(--gray-100); }
.tpl-slider__card:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}
.tpl-slider__card.is-current {
    border-color: var(--color-primary);
    background: var(--color-primary-subtle);
    cursor: default;
}

.tpl-slider__thumb {
    display: block;
    width: 92px;
    height: 130px;                       /* sources range 400x566 to 400x720 (metric,
                                             curriculum, bordeaux are the tallest) — same
                                             top-anchored crop as the gallery, so the CV
                                             name header at the top never gets sliced off */
    object-fit: cover;
    object-position: top center;
    border: 1px solid var(--color-border);
    border-radius: 2px;
    background: var(--gray-100);         /* placeholder while a lazy thumb loads */
}

.tpl-slider__name {
    display: block;
    margin-top: 3px;
    font-size: 11px;
    line-height: 1.3;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Tier as a dot: the full badge text is far wider than a 92px card. */
.tpl-slider__tier {
    display: block;
    width: 6px;
    height: 6px;
    margin: 2px auto 0;
    border-radius: 50%;
}
.tpl-slider__tier--ats      { background: var(--color-success); }
.tpl-slider__tier--hybrid   { background: var(--color-info); }
.tpl-slider__tier--showcase { background: var(--color-warn); }

.tpl-slider__nav {
    flex: 0 0 auto;
    width: 1.75rem;
    height: 2.25rem;
    padding: 0;
    font-size: 1.25rem;
    line-height: 1;
    color: var(--gray-600);
    background: var(--gray-100);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
}
.tpl-slider__nav:hover { background: var(--gray-200); }
.tpl-slider__nav[hidden] { display: none; }

.tpl-slider__clear {
    flex: 0 0 auto;
    font-family: inherit;
    font-size: var(--fs-xs);
    color: var(--color-primary);
    background: none;
    border: none;
    cursor: pointer;
    text-decoration: underline;
}
.tpl-slider__clear[hidden] { display: none; }

@media (max-width: 768px) {
    .tpl-slider { padding: var(--sp-2); }
}

/* No scroll-behavior here on purpose: chevron scrolling is tweened in
   builder.js with rAF, because `scroll-behavior: smooth` and
   `scrollBy({behavior:'smooth'})` are both silent no-ops in some embedded
   browsers, which would leave the chevrons dead rather than un-animated. */

/* funnel: edit-canvas pill gap fix, scoped to the builder only.
   funnel.php's pdf-mode markup separates adjacent <span class="cv-pill">
   siblings with a literal space character in the source, which is the ONLY
   thing producing the 4.14px gap between pills in mPDF (funnel.css
   deliberately carries no margin/padding on .cv-pill — margin is inert on
   an inline-block in mPDF, confirmed there). Edit mode instead renders pills
   via an Alpine `x-for` on a <template>, which clones the pill elements with
   no whitespace text node between them, so #builder-canvas measured 0px
   gaps while #builder-measure (the server's real pdf-mode markup) measured
   4.14px — verified directly via getBoundingClientRect() on both. This rule
   converges the live canvas on that 4.14px without touching funnel.css, so
   the export markup/CSS stays byte-identical. margin-right (not a gap
   property) mirrors the "space after every pill but the last" shape of the
   literal-space export markup; :last-child is skipped so the centered row
   doesn't pick up trailing offset the export never has. */
#builder-canvas .resume-funnel .cv-pill:not(:last-child) {
    margin-right: 4.14px;
}
