/* fox-tokens:light:start - generated by cdn/generate-fox-styles.js from
   cdn/fox-tokens.js. Hand-edit fox-tokens.js, not the values below. */
:root {
    color-scheme: light;

    /* --- Polarfuchs Aesthetic Palette --- */
    --ink: #26343f; /* Deep polar night navy */
    --ink-soft: #4a5a66; /* Frosty slate for secondary text */
    --snow: #fdfdfb; /* Card face / main panel background */
    --dusk: #e8eef2; /* Screen layout backdrop */
    --hairline: #b9c6ce; /* Structured divider borders */

    /* --- Functional Category Signals (AAA Accessible) --- */
    --ice: #9fc4d6; /* Calm / Status */
    --moss: #8fae9b; /* Bedürfnis / Need */
    --dawn: #c96b5e; /* Wichtig / Urgent Crisis */
    /* Added for mtools/bob-tree's 7-way register category encoding, which
       needs more distinct accent hues than the 3-signal set above provides.
       Always paired with a glyph + printed category name, never hue alone. */
    --birch: #c9b38a; /* Bark tan */
    --slate: #7c8fa3; /* Stone blue-grey */
    --aurora: #a68fc9; /* Aurora violet */

    /* --- Overlay/shadow tokens (RGB triples, not resolved rgba(), so each
       call site can keep its own alpha while hue/lightness flips as one
       unit with the theme) --- */
    --shadow-ink: 38, 52, 63; /* box-shadows: stays black-based in dark mode too, see below */
    --overlay-glass: 253, 253, 251; /* glassmorphism panel tint, tracks --snow/--dusk */
    --tint-hairline: 185, 198, 206; /* --hairline tinge, used for subtle fills */
    --tint-ice: 159, 196, 214; /* --ice tinge, used for focus rings/notes */
    --tint-dawn: 201, 107, 94; /* --dawn tinge, used for warning-banner fills */
    --btn-primary-hover: #354756; /* .fox-btn-primary hover step */

    /* Aliases resolved once here so .fox-toolbar/.fox-settings can re-pin
       to them below without duplicating literal colors per theme (see
       those selectors' comments for why the re-pin exists at all). */
    --fox-ink: var(--ink);
    --fox-ink-soft: var(--ink-soft);
    --fox-hairline: var(--hairline);
    --fox-ice: var(--ice);

    /* --- Typography System --- */
    --font-sans: "Atkinson Hyperlegible", system-ui, -apple-system, sans-serif;
    --font-mono: "Atkinson Hyperlegible Mono", "SF Mono", "Cascadia Mono", Consolas, monospace;
    --font-serif: "Sylexiad Serif Medium", Georgia, "Times New Roman", serif;

    /* --- Spacing & Layout Constraints --- */
    --radius-ui: 8px;
    --radius-card: 10px;
}
/* fox-tokens:light:end */

/* --- Self-hosted Typography ---
   Atkinson Hyperlegible (SIL OFL), fetched from Google Fonts' own CDN and
   re-hosted here so --font-sans doesn't depend on a third-party origin at
   all (previously this was referenced by name only, with tools linking
   fonts.googleapis.com directly - see cdn/fox-usage.md). woff2 first for
   browsers, ttf as the fallback format Qt's QFontDatabase/QML's FontLoader
   need instead. Relative URLs so this works whether fox.css is served from
   the real CDN or a local checkout (see masyu/tools/verify-browser.mjs). */
@font-face {
    font-family: "Atkinson Hyperlegible";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("./atkinson-hyperlegible-regular.woff2") format("woff2"),
         url("./atkinson-hyperlegible-regular.ttf") format("truetype");
}
@font-face {
    font-family: "Atkinson Hyperlegible";
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url("./atkinson-hyperlegible-italic.woff2") format("woff2"),
         url("./atkinson-hyperlegible-italic.ttf") format("truetype");
}
@font-face {
    font-family: "Atkinson Hyperlegible";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("./atkinson-hyperlegible-bold.woff2") format("woff2"),
         url("./atkinson-hyperlegible-bold.ttf") format("truetype");
}
@font-face {
    font-family: "Atkinson Hyperlegible";
    font-style: italic;
    font-weight: 700;
    font-display: swap;
    src: url("./atkinson-hyperlegible-bolditalic.woff2") format("woff2"),
         url("./atkinson-hyperlegible-bolditalic.ttf") format("truetype");
}

/* Atkinson Hyperlegible Mono (SIL OFL, see cdn/OFL-MONO.txt), same
   Braille Institute lineage and re-hosting rationale as the sans block
   above - fetched from the googlefonts/atkinson-hyperlegible-next-mono
   repo's own static instances. */
@font-face {
    font-family: "Atkinson Hyperlegible Mono";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("./atkinson-hyperlegible-mono-regular.woff2") format("woff2"),
         url("./atkinson-hyperlegible-mono-regular.ttf") format("truetype");
}
@font-face {
    font-family: "Atkinson Hyperlegible Mono";
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url("./atkinson-hyperlegible-mono-italic.woff2") format("woff2"),
         url("./atkinson-hyperlegible-mono-italic.ttf") format("truetype");
}
@font-face {
    font-family: "Atkinson Hyperlegible Mono";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("./atkinson-hyperlegible-mono-bold.woff2") format("woff2"),
         url("./atkinson-hyperlegible-mono-bold.ttf") format("truetype");
}
@font-face {
    font-family: "Atkinson Hyperlegible Mono";
    font-style: italic;
    font-weight: 700;
    font-display: swap;
    src: url("./atkinson-hyperlegible-mono-bolditalic.woff2") format("woff2"),
         url("./atkinson-hyperlegible-mono-bolditalic.ttf") format("truetype");
}

/* Sylexiad Serif Medium, self-hosted under Robert Hillier's own EULA (see
   cdn/LICENSE-SYLEXIAD.txt) - not SIL OFL like the two font families above.
   Free for commercial/personal/educational use and web embedding, but the
   files must not be independently redistributable and the credit line
   below is a license term, not a courtesy: "Sylexiad Serif Medium" by
   Robert Hillier (sylexiad.com), used under EULA. */
@font-face {
    font-family: "Sylexiad Serif Medium";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("./sylexiad-serif-medium-regular.woff2") format("woff2"),
         url("./sylexiad-serif-medium-regular.ttf") format("truetype");
}
@font-face {
    font-family: "Sylexiad Serif Medium";
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url("./sylexiad-serif-medium-italic.woff2") format("woff2"),
         url("./sylexiad-serif-medium-italic.ttf") format("truetype");
}
@font-face {
    font-family: "Sylexiad Serif Medium";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("./sylexiad-serif-medium-bold.woff2") format("woff2"),
         url("./sylexiad-serif-medium-bold.ttf") format("truetype");
}
@font-face {
    font-family: "Sylexiad Serif Medium";
    font-style: italic;
    font-weight: 700;
    font-display: swap;
    src: url("./sylexiad-serif-medium-bolditalic.woff2") format("woff2"),
         url("./sylexiad-serif-medium-bolditalic.ttf") format("truetype");
}

/* --- Dark palette ---
   Applies automatically via OS preference unless the page opts out with
   data-theme="light", and can be forced on with data-theme="dark"
   regardless of OS preference. Mirrors the pattern already used in
   mtools/puzzle/report-template.html so the whole repo stays consistent.
   Functional signal hues are lifted (not mirrored) — a literal luminance
   mirror of these already-midtone accents goes muddy on a dark backdrop
   and breaks the "AAA Accessible" intent documented above. --shadow-ink
   stays black-based in both themes since a shadow represents occluded
   light, not a themed surface. */
@media (prefers-color-scheme: dark) {
    /* fox-tokens:media-dark:start */
    :root:where(:not([data-theme="light"])) {
        color-scheme: dark;
        --ink: #e7edf1;
        --ink-soft: #b6c4cd;
        --snow: #1e262d;
        --dusk: #12171b;
        --hairline: #3a4750;
        --ice: #8fc9e6;
        --moss: #9fc4ab;
        --dawn: #e08a7d;
        --birch: #dcc9a3;
        --slate: #9db0c4;
        --aurora: #bfa8e0;
        --shadow-ink: 0, 0, 0;
        --overlay-glass: 20, 26, 31;
        --tint-hairline: 58, 71, 80;
        --tint-ice: 143, 201, 230;
        --tint-dawn: 224, 138, 125;
        --btn-primary-hover: #c3d2db;
    }
    /* fox-tokens:media-dark:end */
}
/* fox-tokens:explicit-dark:start */
:root[data-theme="dark"] {
    color-scheme: dark;
    --ink: #e7edf1;
    --ink-soft: #b6c4cd;
    --snow: #1e262d;
    --dusk: #12171b;
    --hairline: #3a4750;
    --ice: #8fc9e6;
    --moss: #9fc4ab;
    --dawn: #e08a7d;
    --birch: #dcc9a3;
    --slate: #9db0c4;
    --aurora: #bfa8e0;
    --shadow-ink: 0, 0, 0;
    --overlay-glass: 20, 26, 31;
    --tint-hairline: 58, 71, 80;
    --tint-ice: 143, 201, 230;
    /* Was missing here (only the @media dark block above had it) even
       though .fox-banner--warning depends on it - forced dark mode via
       data-theme="dark" was getting the light-mode tint on a dark
       backdrop. Filled in to match, while adding fox-tokens generation. */
    --tint-dawn: 224, 138, 125;
    --btn-primary-hover: #c3d2db;
}
/* fox-tokens:explicit-dark:end */

/* --- Global Reset Blueprint --- */
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}
body {
    font-family: var(--font-sans);
    background: var(--dusk);
    color: var(--ink);
    line-height: 1.5;
}

/* --- Headings (h1-h6) ---
   Headings break from the body sans to Sylexiad Serif Medium, matching the
   foxClass="h1".."h6" scale in fox-light.qss/fox-dark.qss and Godot's
   HeaderLabel variation. The pt scale over there (22/18/15/13/11/9) is
   carried across as rem here. */
h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-serif);
    font-weight: 700;
    color: var(--ink);
}
h1 { font-size: 2rem; }
h2 { font-size: 1.65rem; }
h3 { font-size: 1.375rem; }
h4 { font-size: 1.185rem; }
h5 { font-size: 1rem; }
h6 { font-size: 0.815rem; }

/* --- Toolbar (action buttons kept outside the collapsible settings box) ---
   Pins its own copy of the tokens it needs (same guard as .fox-settings
   below), so a page that redefines --ink/--ink-soft/--sans for its own
   content (e.g. puzzle.html's monochrome palette) can't leak into this
   shared chrome. */
.fox-toolbar {
    --ink: var(--fox-ink);
    --ink-soft: var(--fox-ink-soft);
    --hairline: var(--fox-hairline);
    --ice: var(--fox-ice);
    font-family: var(--font-sans);
    max-width: 760px;
    margin: 24px auto 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* --- Collapsible Settings Section --- */
.fox-settings {
    --ink: var(--fox-ink);
    --ink-soft: var(--fox-ink-soft);
    --hairline: var(--fox-hairline);
    font-family: var(--font-sans);
    max-width: 760px;
    margin: 24px auto 16px;
    background: rgba(var(--overlay-glass), 0.85); /* Glassmorphism snow */
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid rgba(var(--tint-hairline), 0.5); /* Hairline accent */
    border-radius: var(--radius-card);
    box-shadow: 0 8px 30px rgba(var(--shadow-ink), 0.08), 0 2px 6px rgba(var(--shadow-ink), 0.04);
    overflow: hidden;
    transition: box-shadow 0.3s ease, border-color 0.3s ease;
}

.fox-settings:hover {
    border-color: rgba(var(--tint-hairline), 0.8);
    box-shadow: 0 12px 40px rgba(var(--shadow-ink), 0.12), 0 4px 10px rgba(var(--shadow-ink), 0.06);
}

.fox-settings-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20px 24px;
    cursor: pointer;
    list-style: none; /* Hide default chevron */
    user-select: none;
    background: rgba(var(--overlay-glass), 0.4);
    transition: background-color 0.2s ease;
}

.fox-settings-header::-webkit-details-marker {
    display: none; /* Safari default marker reset */
}

.fox-settings-header:hover {
    background: rgba(var(--overlay-glass), 0.8);
}

.fox-settings-header:focus-visible {
    outline: 2px solid var(--ice);
    outline-offset: -2px;
}

.fox-settings-title-wrap {
    display: flex;
    align-items: center;
    gap: 12px;
}

.fox-settings-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ink);
}

.fox-settings-title {
    font-family: var(--font-sans);
    font-size: 1.35rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--ink);
}

.fox-settings-chevron {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    color: var(--ink-soft);
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Rotate chevron when open */
.fox-settings[open] .fox-settings-chevron {
    transform: rotate(180deg);
}

.fox-settings-content {
    padding: 0 24px 24px 24px;
    border-top: 1px solid rgba(var(--tint-hairline), 0.3);
    background: rgba(var(--overlay-glass), 0.2);
}

.fox-settings-desc {
    margin: 16px 0 20px;
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--ink-soft);
    max-width: 65ch;
}

/* --- Form Controls & Grid --- */
.fox-cfg-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 12px 16px;
    margin-bottom: 16px;
}

.fox-field-group {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.fox-label {
    display: block;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-soft);
}

.fox-input, .fox-select, .fox-textarea {
    width: 100%;
    font-family: var(--font-sans);
    font-size: 0.9rem;
    padding: 8px 12px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    background: var(--snow);
    color: var(--ink);
    transition: border-color 0.2s ease, box-shadow 0.2s ease, outline 0.2s ease;
}

.fox-input:focus, .fox-select:focus, .fox-textarea:focus {
    outline: none;
    border-color: var(--ice);
    box-shadow: 0 0 0 3px rgba(var(--tint-ice), 0.3);
}

/* --- Grouped Field Boxes (bundle related fields into one box) --- */
.fox-group-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 18px 16px;
    margin-bottom: 16px;
}

.fox-group-box {
    background: rgba(var(--tint-hairline), 0.18);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    padding: 12px 14px 14px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    box-shadow: 0 1px 2px rgba(var(--shadow-ink), 0.06);
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.fox-group-box:hover {
    border-color: var(--ink-soft);
    box-shadow: 0 4px 10px rgba(var(--shadow-ink), 0.1);
}

.fox-group-title {
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--ink);
    padding-bottom: 8px;
    border-bottom: 1px solid var(--hairline);
}

.fox-group-fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
    gap: 10px 12px;
}

/* --- Buttons System --- */
.fox-btn-row {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: 20px;
}

.fox-btn {
    font-family: var(--font-sans);
    font-size: 0.875rem;
    font-weight: 700;
    padding: 10px 20px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    background: var(--snow);
    color: var(--ink);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    user-select: none;
    transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275),
                background-color 0.2s ease,
                border-color 0.2s ease,
                box-shadow 0.2s ease;
}

.fox-btn:hover {
    background: rgba(var(--tint-hairline), 0.1);
    border-color: var(--ink-soft);
    transform: translateY(-1px);
    box-shadow: 0 4px 8px rgba(var(--shadow-ink), 0.05);
}

.fox-btn:active {
    transform: translateY(0);
    box-shadow: none;
}

.fox-btn-primary {
    background: var(--ink);
    color: var(--snow);
    border-color: var(--ink);
}

.fox-btn-primary:hover {
    background: var(--btn-primary-hover);
    border-color: var(--btn-primary-hover);
    color: var(--snow);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(var(--shadow-ink), 0.15);
}

.fox-btn-primary:active {
    background: var(--ink);
}

.fox-btn:focus-visible {
    outline: 2px solid var(--ice);
    outline-offset: 2px;
}

/* Layered on .fox-btn like .fox-btn-primary; wired up by
   PolarfuchsSystem.initTheme() via the [data-fox-theme-toggle] hook. */
.fox-theme-toggle {
    min-width: 128px; /* avoid layout shift between "Dark mode"/"Light mode" labels */
}

/* --- Totals & Info elements --- */
.fox-totals {
    font-family: var(--font-mono);
    font-size: 0.8rem;
    color: var(--ink-soft);
    margin: 16px 0 8px;
    padding: 6px 10px;
    background: rgba(var(--tint-hairline), 0.15);
    border-radius: var(--radius-ui);
    display: inline-block;
}

.fox-print-note {
    font-size: 0.8rem;
    line-height: 1.5;
    background: rgba(var(--tint-ice), 0.1);
    border-left: 3px solid var(--ice);
    padding: 12px 16px;
    border-radius: 0 var(--radius-ui) var(--radius-ui) 0;
    margin-top: 20px;
    color: var(--ink-soft);
}

.fox-print-note ol, .fox-print-note ul {
    margin-left: 20px;
    margin-top: 8px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.fox-legend {
    font-size: 0.8rem;
    line-height: 1.5;
    background: rgba(var(--tint-hairline), 0.1);
    border-left: 3px solid var(--hairline);
    padding: 12px 16px;
    border-radius: 0 var(--radius-ui) var(--radius-ui) 0;
    margin-top: 16px;
    color: var(--ink);
}

.fox-legend-detail {
    color: var(--ink-soft);
    font-weight: normal;
    margin-left: 8px;
}

.fox-print-note > strong:first-of-type,
.fox-legend > strong:first-of-type {
    display: block;
    font-size: 0.85rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 8px;
    color: var(--ink);
}

/* --- Banners (non-blocking advisory notices) ---
   Same left-border-callout language as .fox-print-note/.fox-legend, but
   meant for dismissible/conditional messages (staleness, reprint,
   overflow) rather than static instructional copy. */
.fox-banner {
    font-size: 0.85rem;
    line-height: 1.5;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    background: rgba(var(--tint-hairline), 0.1);
    border-left: 3px solid var(--hairline);
    padding: 12px 16px;
    border-radius: 0 var(--radius-ui) var(--radius-ui) 0;
    margin: 16px 0;
    color: var(--ink);
}

.fox-banner--warning {
    background: rgba(var(--tint-dawn), 0.12);
    border-left-color: var(--dawn);
}

/* --- Save-state indicator ---
   .fox-totals's pill styling, repurposed as a dirty/saving/saved/error
   readout. The state lives in data-state so a consumer can transition it
   without rebuilding the element. */
.fox-savestate {
    font-family: var(--font-mono);
    font-size: 0.8rem;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    border-radius: var(--radius-ui);
    background: rgba(var(--tint-hairline), 0.15);
    color: var(--ink-soft);
}

.fox-savestate[data-state="saving"] { opacity: 0.7; }
.fox-savestate[data-state="dirty"] { background: rgba(var(--tint-ice), 0.25); }
.fox-savestate[data-state="error"] {
    border: 1px solid var(--dawn);
    color: var(--dawn);
    background: rgba(var(--tint-dawn), 0.1);
}

/* --- Card Editor Specifics --- */
.fox-editor-row {
    background: rgba(var(--tint-hairline), 0.1);
    border: 1px solid rgba(var(--tint-hairline), 0.4);
    border-radius: var(--radius-ui);
    padding: 14px;
    margin-bottom: 12px;
    display: grid;
    grid-template-columns: 1fr 1fr auto;
    gap: 12px;
    align-items: start;
    transition: border-color 0.2s ease;
}

.fox-editor-row:hover {
    border-color: var(--hairline);
}

.fox-row-meta {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 130px;
}

.fox-big-toggle {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    user-select: none;
    color: var(--ink-soft);
}

.fox-big-toggle input[type="checkbox"] {
    width: 14px;
    height: 14px;
    accent-color: var(--ink);
    cursor: pointer;
}

/* --- Print Rules --- */
@media print {
    .fox-settings, .fox-toolbar {
        display: none !important;
    }
}

@media screen and (max-width: 700px) {
    .fox-editor-row {
        grid-template-columns: 1fr;
    }
    .fox-group-grid {
        grid-template-columns: 1fr;
    }
}

/* ============================================================
   Print Sheet Mechanics
   Shared by any tool that lays out A7-ish cutout-card grids
   (mtools/cards, mtools/rules) or A5-ish half-sheets
   (mtools/puzzle) via fox-sheets.js. Dimensions are supplied
   per-sheet as CSS custom properties by the JS renderer, so the
   same classes serve both A4-portrait grid sheets and
   A4-landscape half sheets.
   ============================================================ */

/* Pinned to light literals (not the --fox-* alias trick) since this
   previews literal paper output on-screen — printed paper is white
   regardless of the page's theme, and must never flip dark. */
.fox-sheets {
    --ink: #26343f;
    --ink-soft: #4a5a66;
    --snow: #fdfdfb;
    --hairline: #b9c6ce;
    --ice: #9fc4d6;
    --moss: #8fae9b;
    --dawn: #c96b5e;
    --birch: #c9b38a;
    --slate: #7c8fa3;
    --aurora: #a68fc9;
    --shadow-ink: 38, 52, 63;
    --overlay-glass: 253, 253, 251;
    --tint-hairline: 185, 198, 206;
    --tint-ice: 159, 196, 214;
    display: flex; flex-direction: column; align-items: center; gap: 18px; padding-bottom: 60px;
}

.fox-sheet {
    width: var(--fox-sheet-w);
    height: var(--fox-sheet-h);
    background: var(--snow);
    box-shadow: 0 2px 14px rgba(38, 52, 63, 0.14);
    position: relative;
}

.fox-sheet--grid {
    /* Duplex registration calibration: printers/copiers rarely align the two
       passes of a duplex job perfectly, so back sheets may need a small
       manual mm correction (set via --fox-duplex-offset-x/-y). This
       reallocates padding between opposite edges rather than transforming
       the sheet itself — .fox-sheet IS the page (fixed size, page-break
       boundary), so moving the whole box just adds blank margin on one
       edge and clips content past the other; shifting padding keeps the
       box's total size (and therefore the page) unchanged and instead
       nudges the grid within it. Front sheets never set the offset
       variables, so this falls back to the original 6.5mm/5mm split there.
       (If a caller passes an explicit `sheetPadding`, that shorthand wins
       outright and offsets don't apply — no current tool does this.) */
    padding: var(--fox-sheet-pad,
        calc(6.5mm + var(--fox-duplex-offset-y, 0mm))
        calc(5mm - var(--fox-duplex-offset-x, 0mm))
        calc(6.5mm - var(--fox-duplex-offset-y, 0mm))
        calc(5mm + var(--fox-duplex-offset-x, 0mm)));
    display: grid;
    grid-template-columns: var(--fox-cols-tpl);
    grid-template-rows: var(--fox-rows-tpl);
}

.fox-sheet--flex {
    display: flex;
    flex-direction: row;
    overflow: hidden;
}

/* --- cards (A7-ish grid) --- */

.fox-card {
    width: var(--fox-card-w);
    height: var(--fox-card-h);
    padding: var(--fox-card-pad, 6mm 7mm 5mm);
    display: flex;
    flex-direction: column;
    position: relative;
    overflow: hidden;
}

.fox-cut-r { border-right: 0.4pt dashed var(--hairline); }
.fox-cut-b { border-bottom: 0.4pt dashed var(--hairline); }

.fox-card-empty { background: none; }

@media screen {
    .fox-card-empty::after {
        content: "";
        position: absolute;
        inset: 5mm;
        border: 0.5pt dashed var(--hairline);
        border-radius: 2mm;
    }
}

/* Opt-in faint guide for the safe-content inset (distinct from fox-cut-r/-b,
   which mark the cut line ON the shared edge between cards). --fox-safe-margin
   sets the inset per card format. Deliberately not @media screen-scoped like
   .fox-card-empty::after above — it must also render (faintly, so it
   disappears under lamination) on the printed sheet, since its whole purpose
   is to guide trimming after printing. */
.fox-safe-margin-guide {
    position: relative;
}
.fox-safe-margin-guide::before {
    content: "";
    position: absolute;
    inset: var(--fox-safe-margin, 5mm);
    border: 0.25pt dashed rgba(var(--tint-hairline), 0.5);
    pointer-events: none;
}

/* Generalizes the recurring "solid / chevron / diagonal-stripe" 3-category
   color+pattern system: colors come from custom properties so each tool's
   own category map supplies its own palette without new CSS. */
.fox-strip {
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 4mm;
}
.fox-strip--solid { background: var(--fox-strip-color); }
.fox-strip--chevron { background: var(--fox-strip-color); }
.fox-strip--chevron svg { display: block; width: 100%; height: 100%; }
.fox-strip--stripe {
    background: repeating-linear-gradient(45deg, var(--fox-stripe-a) 0 3mm, var(--fox-stripe-b) 3mm 6mm);
}

.fox-card .fox-icon { align-self: flex-end; }
.fox-card .fox-icon svg { display: block; width: 10mm; height: 10mm; }

/* --- half-sheets (A5-ish, 2-up) --- */

.fox-half {
    width: var(--fox-half-w);
    height: var(--fox-sheet-h);
    padding: var(--fox-half-pad, 11mm 10mm 9mm);
    display: flex;
    flex-direction: column;
    position: relative;
}
.fox-half + .fox-half { border-left: 1px dashed var(--hairline); }

.fox-cutmark {
    position: absolute;
    left: var(--fox-half-w);
    top: 4mm;
    transform: translateX(-50%);
    background: var(--snow);
    padding: 0.5mm 0;
    line-height: 0;
}
.fox-cutmark.bottom {
    top: auto;
    bottom: 4mm;
    transform: translateX(-50%) rotate(180deg);
}

/* --- print --- */

@media print {
    body { background: #fff; }
    .fox-sheets { gap: 0; padding: 0; display: block; }
    .fox-sheet {
        box-shadow: none;
        page-break-after: always; break-after: page;
        margin: 0 !important;
        transform: none !important;
    }
    /* Without this, some print drivers emit a spurious trailing blank page
       after the last sheet's page-break-after: always. */
    .fox-sheet:last-child { page-break-after: auto; break-after: auto; }
    .fox-strip { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }

@media screen and (max-width: 700px) {
    .fox-sheet {
        transform: scale(var(--fox-scale, 0.44));
        transform-origin: top center;
        margin-bottom: calc(var(--fox-sheet-h) * (var(--fox-scale, 0.44) - 1));
    }
}
