/* ── Resume print & pagination ────────────────────────────────────────────
   Shared paged-media contract for the resume templates (template_1, _2, _6,
   _7). One file serves two consumers:

     @media print  → WeasyPrint, when resume.py attaches this sheet.
     @media screen → the editor's live preview iframe, when a page-break
                     preview class is toggled on.

   WHY EVERY PAGED DECLARATION CARRIES !important
   WeasyPrint's HTML(...).write_pdf(stylesheets=[...]) argument loads a sheet
   at USER origin, not author origin. Measured on WeasyPrint 69.0: against a
   template whose own <style> declares `@page { margin: 0 }`, a plain user
   declaration of `margin: 20mm` was discarded (page margin stayed 0px) and
   only `margin: 20mm !important` applied (75.6px). Templates 1/2/6/7 all
   declare @page, height and padding in an inline <style>, so a corrective
   rule here without !important is silently a no-op. Drop the !important only
   from a property no template declares.

   If instead this file is <link>ed into a template (author origin, requires a
   base_url on the WeasyPrint call), the !important is harmless: it still
   resolves the same way against the template's own declarations.

   HOW A TEMPLATE OPTS OUT OF THE SHARED GEOMETRY
   The page box is driven by custom properties read from :root, never
   redefined here. A template that wants to keep its own margins declares them
   on its own :root, which is author origin and therefore wins:

       :root { --frb-margin-top: 25mm; --frb-margin-side: 25mm;
               --frb-margin-bottom: 25mm; }

   --frb-margin-left and --frb-margin-right each override --frb-margin-side on
   one edge, for a template whose page box is deliberately asymmetric
   (template_14 reserves a 30mm right rail). Set --frb-margin-side alone when
   both edges match.

   Every template that declares its own @page margin now carries this block
   beside that rule, so the shared geometry below reaches only templates 6 and
   7 — the two that supply their inset as padding on a `height: 100%` element
   and are the reason this sheet exists. A NEW template that forgets to set a
   page margin inherits 16/14/16 rather than 0, which is the safe default: the
   defect being fixed here is content at 0mm from the paper edge.
   ────────────────────────────────────────────────────────────────────────── */


/* ── 1. Paged output ─────────────────────────────────────────────────────── */
@media print {

    /* A4 is the default because resume.py's templates all declare `size: A4`
       and the service has no paper-size parameter today. Letter is opt-in via
       a body class so a caller can switch paper without a second stylesheet;
       @page cannot be selected by an element class, so the class maps onto a
       named page, which can. */
    @page {
        size: A4 !important;
        margin:
            var(--frb-margin-top, 16mm)
            var(--frb-margin-right, var(--frb-margin-side, 14mm))
            var(--frb-margin-bottom, 16mm)
            var(--frb-margin-left, var(--frb-margin-side, 14mm)) !important;

        /* Page number is placed in the bottom margin box, so it costs no
           content height and cannot collide with the last line. */
        @bottom-right {
            content: counter(page) " / " counter(pages);
            font: 8pt "Helvetica", Arial, sans-serif;
            color: #9ca3af;
        }

        /* Name repeats on continuation pages: a resume that arrives as loose
           printed sheets is otherwise unattributable past page 1. Filled from
           string(frb-name), set below. */
        @top-left {
            content: string(frb-name);
            font: 8pt "Helvetica", Arial, sans-serif;
            color: #9ca3af;
        }
    }

    /* Page 1 already shows the name at full size in the body. */
    @page :first {
        @top-left { content: none; }
    }

    body.frb-letter { page: frb-letter !important; }

    @page frb-letter {
        size: Letter !important;
        margin:
            var(--frb-margin-top, 16mm)
            var(--frb-margin-right, var(--frb-margin-side, 14mm))
            var(--frb-margin-bottom, 16mm)
            var(--frb-margin-left, var(--frb-margin-side, 14mm)) !important;
    }

    /* Whichever element carries the name across the four templates:
       h1.name (t1), div.name (t2), bare h1 (t6, t7). */
    h1,
    .name {
        string-set: frb-name content() !important;
    }


    /* ── 1a. The clipped-page-2 defect ───────────────────────────────────────
       Templates 6 and 7 lay out as `display: table` with `height: 100%` on
       html/body/.container and all visible inset supplied by padding on the
       table cells. Two failures follow, both fixed here rather than in the
       templates so one sheet covers both files.

       First: under CSS fragmentation padding-top applies only to a box's
       FIRST fragment and padding-bottom only to its LAST. Combined with
       `@page { margin: 0 }` there is no inset left to re-establish on
       continuation pages, so from page 2 text sits flush against the physical
       sheet edge — inside the non-printable margin of every consumer printer,
       which is what reads as "the export is cut off". The inset must live on
       @page (above), which is re-applied per page by definition; the cells'
       vertical padding is therefore removed so the two do not compound on
       page 1. Horizontal padding survives fragmentation intact and is kept as
       the inter-column gutter.

       Second: `height: 100%` forces the table to at least page height, after
       which the sidebar cell measures height 0 on every page past the first
       and its background band stops at the page 1 boundary. Releasing the
       height lets each fragment size to its own content. */
    html,
    body,
    .container {
        height: auto !important;
        min-height: 0 !important;
    }

    /* A fixed height anywhere in the column chain is the other way a final
       line gets clipped, so the release extends to the cells. overflow is
       normalised at the same time: a scroll container does not paginate, it
       truncates. */
    .sidebar,
    .main,
    .left-col,
    .right-col {
        height: auto !important;
        padding-top: 0 !important;
        padding-bottom: 0 !important;
    }

    html,
    body,
    .container,
    .sidebar,
    .main,
    .left-col,
    .right-col {
        overflow: visible !important;
    }

    /* Do not convert these columns to float or flex. Floats do not fragment:
       swapping the table for floated columns collapsed a 3-page document to
       1 page and dropped the overflow outright. display: table fragments
       correctly in WeasyPrint 69 and is the right primitive here. */


    /* ── 1b. Break control ──────────────────────────────────────────────────
       Unprefixed `break-*` is the current property; `page-break-*` is its
       legacy alias. WeasyPrint 69 honours both, and the templates already use
       the legacy spelling on some blocks. Declaring the modern one here at
       user-!important overrides uniformly and covers the blocks the templates
       missed. */

    /* One role, project or qualification must never straddle a page. */
    .job-block,
    .project-block,
    .entry {
        break-inside: avoid !important;
    }

    /* A section heading stranded as the last line of a page is the other
       common paged-media defect. No template sets this today. */
    h1, h2, h3,
    .name,
    .headline,
    .entry-title,
    .job-title {
        break-after: avoid !important;
        break-inside: avoid !important;
    }

    /* An entry's title must stay with the body text underneath it. */
    .entry-head,
    .entry-header,
    .job-company,
    .job-date,
    .entry-sub,
    .entry-date {
        break-after: avoid !important;
    }

    /* The CSS initial value is 2, which still permits a single stranded line
       of a paragraph. No template overrides it. */
    p,
    .desc,
    .entry-desc,
    .summary {
        orphans: 3 !important;
        widows: 3 !important;
    }

    /* Nothing may be dropped from the flow: a paged formatter cannot
       reconstruct content it was told not to render. */
    .job-block,
    .project-block,
    .entry,
    p {
        overflow: visible !important;
    }


    /* ── 1c. Full-bleed sidebar band — deliberately NOT automatic ───────────
       Templates 6 and 7 paint their coloured column on the .sidebar/.left-col
       ELEMENT. Once that column's content is exhausted the cell has nothing
       left to stretch, so the band ends partway down the last page it reaches.
       The usual fix is to move the band onto @page as a linear-gradient, which
       repeats per page for free.

       That is not done here because it would be wrong more often than right.
       Measured on WeasyPrint 69: a page box resolves var() against :root only.
       A custom property defined on :root reached @page; the identical property
       defined on body did not (it computed to transparent). Templates 6 and 7
       declare their palette on :root for the default theme but declare every
       theme override on body.theme-ocean / .theme-sunset / .theme-forest and
       body.light-mode. An @page gradient would therefore paint the default
       midnight colours behind every non-default theme the user picks — a
       visible mismatch against the column drawn by the element.

       Enable it per template only once that template's chosen palette is
       reachable from :root, by setting all three properties there. The stop is
       the sidebar's share of the PAGE width, not of the content width:
           stop % = (margin-side + column% x content-width) / paper-width
       For template_7 (30% column, A4, the margins above): 14 + 0.30 x 182
       = 68.6mm of 210mm = 32.7%.

       A template opting in declares BOTH halves itself, because CSS cannot
       detect that --frb-band was set and cancel the element band in response
       (there is no such selector, and the page box is not an ancestor of the
       column):

           :root { --frb-band: linear-gradient(to right,
                       #1e293b 32.7%, #0f172a 32.7%); }
           .sidebar { background-color: transparent !important; }

       Use single-position colour stops, as above. WeasyPrint 69 rejects the
       Images Level 4 two-position form (`#1e293b 0 32.7%`) as an invalid
       value and drops the whole declaration, silently leaving the page
       unpainted — it warns to the log but still renders.

       THE STOP IS A FRACTION OF THE CONTENT BOX, NOT OF THE PAPER. Measured on
       WeasyPrint 69 against A4 with these margins: a stop at 25% landed at
       59.5mm, which is 14mm + 0.25 x 182mm — the positioning area is the page's
       content box, and `background-origin: border-box` does not move it (it is
       ignored on a page box). So a column that is 32% of the content width
       takes a stop of exactly 32%; no paper-relative arithmetic is needed.

       no-repeat below is what makes that usable. Left to repeat, the gradient
       tiles into the margins and the sidebar colour reappears down the far
       edge of the sheet — the observed failure was a dark band inside the right
       margin of an otherwise light page. With no-repeat WeasyPrint still paints
       the full page: measured, the corners outside the content box take the
       adjacent stop's colour, which is exactly the full-bleed the band is for.
       A solid --frb-band (templates 10-19) renders identically either way, so
       this is inert for every current consumer.

       Left unset, the default below is `none`, so this rule is inert and the
       existing element band is untouched. */
    @page {
        background: var(--frb-band, none) !important;
        background-repeat: no-repeat !important;
    }
}


/* ── 2. On-screen page-break preview ──────────────────────────────────────
   Toggled by adding .frb-pagebreak-preview to the resume document's <body>
   INSIDE the preview iframe (the editor's iframe is fed by srcdoc, so this
   sheet and the class both have to be applied to the iframe's own document —
   see the README).

   Everything here is @media screen, so merely injecting this file into the
   iframe changes nothing until the class is set. That keeps the integration
   reversible and means an editor bug cannot alter the exported PDF.

   ACCURACY, STATED HONESTLY. This is a ruler, not a pagination engine. The
   browser lays the document out in one continuous flow; it does not paginate,
   so the rules below can only mark where each page WOULD end. Two sources of
   drift, neither removable in CSS alone:
     - break-inside: avoid pushes a block that would straddle a line down to
       the next page. On screen the block stays put, so every mark after the
       first pushed block sits progressively lower than the real break.
     - The browser and WeasyPrint use different font metrics and line
       breaking, so line counts can differ slightly over a long column.
   The measure is matched to print below, which removes the largest source of
   disagreement; treat the marks as accurate to within about a line until the
   first avoided break. */
@media screen {

    .frb-pagebreak-preview {
        /* Reproduce the print page box on screen. Without this the iframe is
           210mm wide while the printed content column is only 182mm, so text
           wraps at a different width and the marks would be measuring a
           different document from the one exported. */
        box-sizing: border-box;
        padding:
            var(--frb-margin-top, 16mm)
            var(--frb-margin-right, var(--frb-margin-side, 14mm))
            var(--frb-margin-bottom, 16mm)
            var(--frb-margin-left, var(--frb-margin-side, 14mm));

        /* Containing block for the ruler overlay. */
        position: relative;

        --frb-paper-h: 297mm;
        --frb-content-h: calc(
            var(--frb-paper-h)
            - var(--frb-margin-top, 16mm)
            - var(--frb-margin-bottom, 16mm));
    }

    .frb-pagebreak-preview.frb-letter {
        --frb-paper-h: 279.4mm;
    }

    /* Same release as the paged layer: height: 100% on these templates makes
       the on-screen document exactly one viewport tall, which is why the
       existing preview shows page 1 and nothing else. */
    .frb-pagebreak-preview,
    .frb-pagebreak-preview .container,
    .frb-pagebreak-preview .sidebar,
    .frb-pagebreak-preview .main,
    .frb-pagebreak-preview .left-col,
    .frb-pagebreak-preview .right-col {
        height: auto !important;
        min-height: 0 !important;
        overflow: visible !important;
    }

    .frb-pagebreak-preview .sidebar,
    .frb-pagebreak-preview .main,
    .frb-pagebreak-preview .left-col,
    .frb-pagebreak-preview .right-col {
        padding-top: 0 !important;
        padding-bottom: 0 !important;
    }

    /* The ruler. One repeating gradient whose period is exactly the printed
       content height, offset so the first mark lands one full page of content
       below where content starts. Drawn on ::after rather than as a body
       background because the templates paint their own opaque background on
       body, which would cover it. */
    .frb-pagebreak-preview::after {
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        height: 100%;
        pointer-events: none;
        z-index: 9999;
        background-repeat: repeat-y;
        background-position: 0 var(--frb-margin-top, 16mm);
        background-image: repeating-linear-gradient(
            to bottom,
            transparent 0,
            transparent calc(var(--frb-content-h) - 9mm),
            var(--frb-break-tint, rgba(239, 68, 68, .07)) calc(var(--frb-content-h) - 9mm),
            var(--frb-break-tint, rgba(239, 68, 68, .07)) calc(var(--frb-content-h) - 2px),
            var(--frb-break-line, rgba(239, 68, 68, .85)) calc(var(--frb-content-h) - 2px),
            var(--frb-break-line, rgba(239, 68, 68, .85)) var(--frb-content-h)
        );
    }
}


/* ── 3. Editor shell helpers ──────────────────────────────────────────────
   These target the EDITOR page, not the resume document — the .paper wrapper
   that holds the preview iframe. The editor pins .paper to a single 297mm
   sheet with overflow: hidden, so a multi-page resume is cropped to page 1 on
   screen regardless of anything the iframe does. That crop is the reason a
   long resume's pagination is only ever discovered at export.

   Applied by adding .frb-preview-paged to the .paper-wrapper. The iframe's
   height still has to be set from its content height in JS — an iframe does
   not size to its document — so this class alone is not sufficient; see the
   README for the one function required. */
.frb-preview-paged .paper {
    height: auto;
    min-height: 297mm;
    overflow: visible;
}

.frb-preview-paged iframe {
    display: block;
    width: 100%;
    /* Replaced from JS with the iframe's real scrollHeight. The fallback keeps
       a single sheet visible if that measurement has not run yet. */
    height: var(--frb-frame-h, 297mm);
}
