/*
 * Sapphire template — corporate photo layout with a dated left gutter.
 * Shared by browser (edit) and mPDF (pdf). No flexbox, no CSS grid:
 * floats / tables / block layout only, so the two renderers agree.
 */

/* ---- page margins (multi-page) ---------------------------------------- *
 * PdfService gives mPDF margin_* = 0, so a PDF's only vertical margin is
 * this wrapper's own padding — and a wrapper's padding-top lands on page 1
 * alone, leaving every later page hard against the sheet edge.
 *
 * @page restores an identical margin on every page; `@page :first` zeroes
 * the top one so page 1 keeps using the wrapper padding it always had and
 * its output is unchanged. Left/right stay 0 — the wrapper's horizontal
 * padding already applies to every page. Inert in the browser (@page is
 * print-only), and builder.js reads these same values back out of CSSOM
 * so its page-count model matches what mPDF actually does. */
@page {
    margin: 44px 0 44px 0;
}
@page :first {
    margin-top: 0;
}

.resume-page {
    width: 794px;              /* A4 @ 96dpi -> fills A4 width in mPDF */
    box-sizing: border-box;
    /* Bottom padding is 0 on purpose (the pulse rule): wrapper bottom padding
       is real trailing space in the flow, so content ending near the boundary
       makes mPDF open a further page and paint nothing on it — measured here
       once the in-cell fix gave the entries their true height, as a blank
       third page on _long.json. The bottom gap on every page comes from
       @page's margin-bottom (44px, below) instead, which does not add to the
       flow. */
    padding: 44px 52px 0;
    background: #ffffff;
    color: #1f2430;
    font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif;
    font-size: 11px;
    line-height: 1.45;
}

/* mPDF does NOT inherit font-family/size into table cells — anything inside
   a <td> silently falls back to the serif document default (in-td trap class,
   2026-07 slate rework). This template's row/column/band layout uses tables,
   so the font must be declared at td level too. No-op in the browser. */
.resume-sapphire td {
    font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif;
    font-size: 11px;
    line-height: 1.45;
    color: #1f2430;
}


/* ---- header ---------------------------------------------------------- */
.resume-sapphire .cv-header {
    margin-bottom: 18px;
    padding-bottom: 14px;
    border-bottom: 2px solid #1e3a8a;
}
.resume-sapphire .cv-photo-wrap {
    float: left;
    width: 96px;
    margin-right: 18px;
}
.resume-sapphire .cv-photo,
.resume-sapphire .cv-photo-initials {
    display: block;
}
.resume-sapphire .cv-header-text {
    overflow: hidden;
    padding-top: 4px;
}
.resume-sapphire .cv-clear {
    clear: both;
}
.resume-sapphire .cv-name {
    font-size: 30px;
    font-weight: bold;
    color: #1e3a8a;
    margin: 0 0 4px;
    line-height: 1.1;
}
.resume-sapphire .cv-jobtitle {
    font-family: 'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
    font-style: italic;
    font-size: 14px;
    color: #1e3a8a;
    margin: 0 0 8px;
}
.resume-sapphire .cv-contact {
    font-size: 10.5px;
    color: #444;
}
.resume-sapphire .cv-contact-item {
    white-space: nowrap;
}
.resume-sapphire .cv-contact-sep {
    color: #9ca3af;
    margin: 0 8px;
}
.resume-sapphire .cv-icon {
    display: inline-block;
    margin-right: 4px;
    font-size: 10px;
}
.resume-sapphire .cv-icon.cv-icon-linkedin {
    color: #ffffff;
    padding: 0 3px;
    border-radius: 2px;
    font-size: 9px;
    font-weight: bold;
}

/* ---- sections -------------------------------------------------------- */
.resume-sapphire .cv-section {
    margin-bottom: 16px;
}
/* pdf mode: mPDF doesn't reliably honor :last-child, so the server marks
 * whichever section/item actually renders last with this plain class
 * instead (sapphire.php). Unscoped on purpose. */
.resume-sapphire .is-last {
    margin-bottom: 0;
}
.resume-sapphire .cv-section-title {
    font-size: 15px;
    font-weight: bold;
    color: #1e3a8a;
    margin: 0 0 8px;
    padding-bottom: 4px;
    border-bottom: 2px solid #1e3a8a;
    page-break-after: avoid;
}
/* page-break-after:avoid on the title alone is not reliable in mPDF — a
 * header can still land as the last line on a page with its first entry
 * pushed to the next one. Wrapping the title together with its first entry
 * in a page-break-inside:avoid group moves the pair to the next page as a
 * unit. */
.resume-sapphire .cv-section-head-group {
    page-break-inside: avoid;
}
.resume-sapphire .cv-summary {
    text-align: left;
}

/* ---- experience / education (three-cell dated gutter) ---------------- */
/* Inter-entry spacing is margin-TOP on a class sapphire.php adds to every entry
 * but the first, never margin-bottom + :last-child (skill §5, and the same
 * conversion capitale needed). Two things were wrong with the old pair:
 *   - margin-bottom on a page-break-inside:avoid block repeated many times
 *     double-counts in mPDF's own pagination-height estimate. Once the in-cell
 *     fix above made the entries their true height, that reserve was enough to
 *     open an entirely blank third page on _long.json.
 *   - the first entry of each section is the last child of
 *     .cv-section-head-group, so Chrome zeroed its margin and glued entry 1 to
 *     entry 2 while mPDF, which ignores :last-child, kept the 12px.
 * A plain class fixes both: an entry without it simply has no top margin, so
 * nothing ever carries a competing value. Not the `+` sibling combinator —
 * mPDF ignores that outright. */
.resume-sapphire .cv-item {
    position: relative;
    page-break-inside: avoid;
}
.resume-sapphire .cv-item--gap {
    margin-top: 12px;
}
.resume-sapphire .cv-row {
    width: 100%;
    border-collapse: collapse;
}
.resume-sapphire .cv-row td {
    vertical-align: top;
    padding: 0;
}
.resume-sapphire .cv-row-dates {
    width: 130px;
    font-size: 10.5px;
    font-weight: bold;
    color: #1e3a8a;
    padding-right: 10px;
}
.resume-sapphire .cv-row-main {
    text-align: left;
}
.resume-sapphire .cv-row-loc {
    width: 120px;
    text-align: right;
    color: #6b7280;
    font-size: 10px;
    padding-left: 10px;
}
.resume-sapphire .cv-item-title {
    font-weight: bold;
    display: block;
}
/* pdf mode: everything below an entry's header line, indented to sit under the
 * middle column of .cv-row (content width 690 - 130 dates - 120 location).
 *
 * It lives OUT of td.cv-row-main on purpose. mPDF renders a display:block span
 * inside a cell as inline and drops ul/li margins there, so the export used to
 * put the position and the company on the same baseline and pack the bullets
 * flat against the title — 332px shorter than the canvas on _long.json. Plain
 * block margins in normal flow are honoured by both renderers, which is the
 * same primitive pulse and monospace were converted to. */
.resume-sapphire .cv-item-body {
    margin-left: 130px;
    margin-right: 120px;
}
.resume-sapphire .cv-item-org {
    font-style: italic;
    color: #374151;
    display: block;
}
.resume-sapphire .cv-item-field {
    color: #6b7280;
    display: block;
}
.resume-sapphire .cv-item-details {
    margin-top: 3px;
}

/* Bullets */
.resume-sapphire .cv-bullets {
    margin: 5px 0 0;
    padding-left: 18px;
}
.resume-sapphire .cv-bullets li {
    margin-bottom: 2px;
}

/* ---- skills / languages / certifications (edit mode: float grid) ------
 * mPDF doesn't reliably pack repeated same-direction floats into rows
 * (confirmed: two adjacent `float:left` items stack instead of sitting
 * side by side, even with explicit widths — cvg-template skill §5), so pdf
 * mode renders these three sections as real `<table class="cv-grid-table">`
 * grids instead (sapphire.php). Everything below through cv-muted is the
 * browser-only float version edit mode still uses. */
.resume-sapphire .cv-skills-cols {
    overflow: hidden;
}
.resume-sapphire .cv-skill-item {
    float: left;
    width: 50%;
    box-sizing: border-box;
    padding: 2px 10px 2px 0;
    font-size: 11px;
}

.resume-sapphire .cv-lang-grid {
    overflow: hidden;
}
.resume-sapphire .cv-lang-cell {
    position: relative;
    float: left;
    width: 33.333%;
    box-sizing: border-box;
    padding: 0 10px 8px 0;
}
.resume-sapphire .cv-level {
    font-size: 10px;
    color: #6b7280;
}
.resume-sapphire .cv-dot-on {
    color: #1e3a8a;
}
.resume-sapphire .cv-dot-off {
    color: #d1d5db;
}

.resume-sapphire .cv-cert-cols {
    overflow: hidden;
}
.resume-sapphire .cv-cert-item {
    position: relative;
    float: left;
    width: 50%;
    box-sizing: border-box;
    padding: 0 10px 4px 14px;
    font-size: 10.5px;
    page-break-inside: avoid;
}
.resume-sapphire .cv-cert-marker {
    display: inline-block;
    width: 12px;
    margin-left: -14px;
    color: #1e3a8a;
}
.resume-sapphire .cv-item-side {
    float: right;
    color: #6b7280;
    font-size: 10px;
}
.resume-sapphire .cv-muted {
    color: #9ca3af;
}

/* pdf mode: table-based grids (mPDF-safe replacement for the floats above). */
.resume-sapphire .cv-grid-table {
    width: 100%;
    border-collapse: collapse;
}
/* The three cell classes below deliberately declare NO padding.
 *
 * `.cv-grid-table td` and each cell class both match the same <td>. A browser
 * applies `padding: 0` from the td rule (higher specificity), so the canvas
 * has never shown the cell padding these classes used to declare. mPDF
 * applied the CLASS instead — a cross-renderer cascade divergence.
 *
 * WHY, corrected 2026-09 (the earlier note here blamed source order; that was
 * wrong and would have sent the next reader after a fix that cannot work):
 * mPDF computes no specificity at all. `Css/CssMerger.php::mergeDescendantCss()`
 * merges matching descendant rules in the fixed category ladder
 *   tag → class → id → tag.class
 * each overwriting the last, so a rule ending in a bare class beats one
 * ending in a bare tag no matter how specific either is. Source order was
 * ruled out empirically — reversing the two rules changes nothing. Raising
 * the td rule's ancestor specificity therefore does NOT help; the working
 * escape hatch is a more specific FINAL simple selector, i.e. writing it as
 * `.resume-sapphire .cv-grid-table td.cv-skill-cell` (verified: `tag.class`
 * is the last rung and wins).
 *
 * Measured divergences, all on _generic.json through the real pipeline:
 *   .cv-skill-cell    `padding: 2px 10px 2px 0`  → +16.0px over the 4-row
 *                     skills grid (rows 20.0px in mPDF vs 15.95px browser)
 *   .cv-lang-cell-pdf `padding: 0 10px 8px 0`    → +8.00px on its 1-row grid
 *   .cv-cert-cell     `padding: 0 10px 4px 14px` → +14.69px vertical AND
 *                     +14.00px horizontal (cert text starts 14px further
 *                     right in the export than on the canvas)
 *   both of the latter together → +22.69px, additive.
 * The last two were originally removed by analogy with the first; these are
 * the measurements confirming they were real, not assumed.
 *
 * One more mechanic found while measuring them, worth knowing before you
 * "fix" this by rewriting a rule as longhands: a SHORTHAND beats a competing
 * LONGHAND in mPDF regardless of the ladder. Restoring `padding-bottom: 4px`
 * or `padding-left: 14px` on .cv-cert-cell alone changed the export by
 * exactly nothing (the td rule's `padding: 0` shorthand still won); only the
 * full `padding: 0 10px 4px 14px` shorthand reproduced the divergence. So the
 * two mechanics compose — the ladder picks between rules of the same kind,
 * and a shorthand outranks a longhand across it.
 *
 * Do not reintroduce padding here: put it on `.cv-grid-table td` if it is
 * ever wanted, where both renderers agree. */
.resume-sapphire .cv-grid-table td {
    vertical-align: top;
    padding: 0;
}
.resume-sapphire .cv-skill-cell {
    width: 50%;
    box-sizing: border-box;
    font-size: 11px;
}
.resume-sapphire .cv-lang-cell-pdf {
    width: 33.333%;
    box-sizing: border-box;
    vertical-align: top;
}
.resume-sapphire .cv-cert-cell {
    width: 50%;
    box-sizing: border-box;
    font-size: 10.5px;
}
.resume-sapphire .cv-cert-date {
    color: #6b7280;
    font-size: 10px;
}

/* =====================================================================
 * Edit-mode affordances (browser only — these elements are never
 * emitted in pdf mode, so none of this reaches mPDF).
 * ===================================================================== */

.resume-sapphire [contenteditable][data-ph]:empty:before,
.resume-sapphire .cv-row-loc:empty:before {
    content: attr(data-ph);
    color: #b7b7b7;
    font-style: italic;
    pointer-events: none;
}
.resume-sapphire [contenteditable] {
    outline: none;
    border-radius: 2px;
    transition: box-shadow 0.12s ease, background 0.12s ease;
}
.resume-sapphire [contenteditable]:hover {
    box-shadow: 0 0 0 1px #c7d2fe;
}
.resume-sapphire [contenteditable]:focus {
    box-shadow: 0 0 0 2px #1e3a8a;
    background: #f5f7ff;
}

.resume-sapphire .edit-controls {
    position: absolute;
    top: -2px;
    right: -44px;
    opacity: 0;
    transition: opacity 0.12s ease;
    white-space: nowrap;
    z-index: 5;
}
.resume-sapphire .edit-controls--inline {
    position: absolute;
    left: -26px;
    right: auto;
    top: 0;
}
.resume-sapphire .cv-item:hover > .edit-controls,
.resume-sapphire .cv-skill-item:hover > .edit-controls,
.resume-sapphire .cv-lang-cell:hover > .edit-controls,
.resume-sapphire .cv-cert-item:hover > .edit-controls,
.resume-sapphire .cv-bullets li:hover > .edit-controls,
.resume-sapphire .edit-controls:hover {
    opacity: 1;
}
.resume-sapphire .edit-controls button {
    font-family: inherit;
    font-size: 13px;
    line-height: 1;
    width: 20px;
    height: 20px;
    margin-left: 2px;
    padding: 0;
    border: 1px solid #ccc;
    background: #fff;
    color: #444;
    border-radius: 3px;
    cursor: pointer;
}
.resume-sapphire .edit-controls button:hover {
    background: #1e3a8a;
    border-color: #1e3a8a;
    color: #fff;
}

.resume-sapphire .cv-add {
    font-family: inherit;
    font-size: 12px;
    margin-top: 6px;
    padding: 4px 10px;
    border: 1px dashed #93a3d1;
    background: #fff;
    color: #1e3a8a;
    border-radius: 4px;
    cursor: pointer;
}
.resume-sapphire .cv-add:hover {
    background: #f5f7ff;
    border-color: #1e3a8a;
}
.resume-sapphire .cv-add--sm {
    font-size: 11px;
    padding: 2px 8px;
}

.resume-sapphire .cv-current {
    display: block;
    font-family: inherit;
    font-size: 10px;
    font-weight: normal;
    color: #6b7280;
    margin-top: 4px;
    white-space: nowrap;
    cursor: pointer;
}
.resume-sapphire .cv-current input {
    vertical-align: middle;
}

.resume-sapphire .cv-tag-x {
    font-family: inherit;
    border: none;
    background: none;
    color: #b00;
    cursor: pointer;
    padding: 0 0 0 4px;
    opacity: 0;
    font-size: 13px;
}
.resume-sapphire .cv-skill-item:hover .cv-tag-x {
    opacity: 1;
}

.resume-sapphire .cv-dot-btn {
    font-family: inherit;
    font-size: 10px;
    line-height: 1;
    width: 12px;
    height: 12px;
    padding: 0;
    margin: 0 1px;
    border: none;
    background: none;
    cursor: pointer;
}
.resume-sapphire .cv-level-toggle {
    font-family: inherit;
    font-size: 9px;
    line-height: 1;
    padding: 1px 3px;
    margin-left: 3px;
    border: 1px solid #ccc;
    background: #fff;
    color: #777;
    border-radius: 2px;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.12s ease;
}
.resume-sapphire .cv-lang-cell:hover .cv-level-toggle {
    opacity: 1;
}
.resume-sapphire .cv-level-text {
    display: inline-block;
    min-width: 20px;
}
