/* ============================================================
   Scribe — Custom Journal Request (the commission concept)

   The second design-your-own concept, running beside the Atelier
   rather than replacing it. Scoped entirely under .cmn so the two
   can sit side by side without either one's vocabulary leaking.

   The Atelier is a workbench: a live journal, a rail of controls,
   a price that moves as you build. This is a commission form —
   numbered rows read top to bottom, and what travels with you is
   not a preview of the product but a brief, because the product
   has not been designed yet. That difference is the concept, so
   it is what the layout below is protecting.
   ============================================================ */

.cmn {
    /* warm, pale, and a touch pinker than the site default */
    --k-ink: #4A3528;
    --k-ink-2: #6B5241;
    --k-muted: #9A8778;
    --k-faint: #B6A395;
    --k-line: #E6D8D0;
    --k-line-soft: #EFE4DD;
    --k-bg: #FAF4F0;
    --k-panel: #F3E8E2;
    --k-panel-2: #F7EDE8;
    --k-card: #FFFFFF;
    --k-accent: #A8705C;
    --k-accent-soft: #F2DDD5;
    --k-deep: #5C3A2E;
    --k-gold: #B08A3C;
    --k-gold-lit: #E3C77E;

    --k-serif: var(--font-display);
    --k-sans: var(--font-body);

    /* Leather grain, baked from feTurbulence to a data URI so the swatches need
       no image files. Range-compressed around mid-grey so soft-light keeps it a
       texture rather than a haze. */
    --k-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.78' numOctaves='4' seed='11'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='0.34' intercept='0.33'/%3E%3CfeFuncG type='linear' slope='0.34' intercept='0.33'/%3E%3CfeFuncB type='linear' slope='0.34' intercept='0.33'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");
    --k-grain-coarse: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.16' numOctaves='3' seed='5'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='0.5' intercept='0.26'/%3E%3CfeFuncG type='linear' slope='0.5' intercept='0.26'/%3E%3CfeFuncB type='linear' slope='0.5' intercept='0.26'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23g)'/%3E%3C/svg%3E");
    --k-grain-fine: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.5' numOctaves='2' seed='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='0.28' intercept='0.36'/%3E%3CfeFuncG type='linear' slope='0.28' intercept='0.36'/%3E%3CfeFuncB type='linear' slope='0.28' intercept='0.36'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23g)'/%3E%3C/svg%3E");

    background: var(--k-bg);
    color: var(--k-ink);
    font-size: 15px;
}

/* The charm shelves reused outside the commission page — on a ready-to-ship
   journal, where they are a section of somebody else's layout rather than the
   page itself. Keeps the tokens and the tiles, drops the page furniture. */
.cmn.cmn-inline {
    background: none;
    font-size: inherit;
    color: inherit;
}

.cmn .sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Every selection control on the page is a label wrapping a hidden input, so
   the checked state is pure CSS and the script only has to keep the brief and
   the estimate in step. Charms are checkboxes (a cover takes several); the rest
   are radios. */
.cmn input[type="radio"], .cmn input[type="checkbox"] {
    position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none;
}


/* ==================== MASTHEAD ==================== */
.cmn-head {
    display: flex; align-items: flex-start; justify-content: space-between; gap: 2.5rem;
    max-width: 1420px; margin: 0 auto;
    padding: clamp(1.8rem, 4vw, 3rem) clamp(1.2rem, 3vw, 3rem) clamp(1.4rem, 3vw, 2rem);
}
.cmn-head h1 {
    font-family: var(--k-serif); font-weight: 400;
    font-size: clamp(2rem, 3.6vw, 2.9rem); line-height: 1.1;
    color: var(--k-deep); margin: 0 0 .7rem; letter-spacing: -.01em;
}
.cmn-head-main p {
    margin: 0; max-width: 52ch; color: var(--k-ink-2);
    font-size: .96rem; line-height: 1.6;
}
.cmn-head-note {
    display: flex; align-items: flex-start; gap: .7rem; flex: none;
    margin: .5rem 0 0; max-width: 30ch;
    font-size: .84rem; line-height: 1.55; color: var(--k-ink-2); font-style: italic;
}
.cmn-head-note .ico { color: var(--k-accent); flex: none; }
.cmn-head-note svg { width: 20px; height: 20px; display: block; }


/* ==================== HOW IT WORKS ==================== */
.cmn-how {
    max-width: 1420px; margin: 0 auto;
    padding: 1.6rem clamp(1.2rem, 3vw, 3rem) 1.8rem;
    border-top: 1px solid var(--k-line);
    border-bottom: 1px solid var(--k-line);
    background: linear-gradient(to bottom, #FDF8F5, var(--k-bg));
}
.cmn-how h2 {
    font-family: var(--k-sans); font-size: .72rem; font-weight: 800;
    letter-spacing: .2em; text-transform: uppercase; color: var(--k-accent);
    margin: 0 0 1.1rem; text-align: center;
}
.cmn-how ol {
    display: grid; grid-template-columns: repeat(5, 1fr); gap: .4rem;
    list-style: none; margin: 0; padding: 0; counter-reset: none;
}
.cmn-how li {
    position: relative; padding: 0 1rem; text-align: center;
}
/* the thread between the steps — one continuous line, like stitching */
.cmn-how li + li::before {
    content: ""; position: absolute; left: -50%; right: 50%; top: 15px;
    border-top: 1px dashed #DFCCC2;
}
.cmn-how .n {
    position: relative; z-index: 1;
    display: grid; place-items: center; width: 31px; height: 31px; margin: 0 auto .55rem;
    border-radius: 50%; background: var(--k-bg);
    border: 1px solid #E3CFC5; box-shadow: 0 0 0 4px var(--k-bg);
    font-family: var(--k-serif); font-size: .88rem; color: var(--k-accent);
}
.cmn-how b {
    display: block; font-family: var(--k-serif); font-weight: 600;
    font-size: .95rem; color: var(--k-ink); line-height: 1.3; margin-bottom: .2rem;
}
.cmn-how-blurb { display: block; font-size: .78rem; color: var(--k-muted); line-height: 1.5; }

.cmn-alert {
    max-width: 1420px; margin: 1.2rem auto 0;
    padding: .85rem 1.2rem; border-radius: 8px;
    background: #FBEAE4; border: 1px solid #E9C2B4; color: #8A4433;
    font-size: .9rem; font-weight: 600;
}


/* ==================== LAYOUT ==================== */
.cmn-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 384px;
    gap: clamp(1.5rem, 3vw, 3rem);
    align-items: start;
    max-width: 1420px; margin: 0 auto;
    padding: 0 clamp(1.2rem, 3vw, 3rem) 5rem;
}
.cmn-form { min-width: 0; }


/* ==================== A NUMBERED ROW ==================== */
.cmn-row {
    display: grid; grid-template-columns: 200px minmax(0, 1fr);
    gap: clamp(1rem, 2.4vw, 2.4rem);
    padding: 1.7rem 0;
    border-bottom: 1px solid var(--k-line-soft);
    scroll-margin-top: 96px;
}
.cmn-row-last { border-bottom: none; }

.cmn-row-label { display: grid; grid-template-columns: auto 1fr; gap: .8rem; align-items: start; }
.cmn-row-label .num {
    font-family: var(--k-sans); font-size: .74rem; font-weight: 700;
    color: var(--k-faint); letter-spacing: .04em; padding-top: .15rem;
    font-variant-numeric: tabular-nums;
}
.cmn-row-label h2 {
    font-family: var(--k-sans); font-size: .76rem; font-weight: 800;
    letter-spacing: .13em; text-transform: uppercase; color: var(--k-ink);
    margin: 0 0 .3rem; line-height: 1.35;
}
.cmn-row-label p {
    margin: 0; font-size: .8rem; line-height: 1.5; color: var(--k-muted);
}
.cmn-row-note { margin: .7rem 0 0; font-size: .76rem; color: var(--k-faint); font-style: italic; }

/* The mark that says "chosen". A ring on the option cards, a filled tick on the
   swatches and charms where a ring would be lost against the artwork. */
.cmn-radio {
    position: absolute; top: .6rem; right: .6rem;
    width: 17px; height: 17px; border-radius: 50%;
    border: 1.5px solid #DCC9BF; background: #fff;
    transition: border-color .18s, background .18s, box-shadow .18s;
}
.cmn-radio::after {
    content: ""; position: absolute; inset: 3px; border-radius: 50%;
    background: var(--k-accent);
    opacity: 0; transform: scale(.4);
    transition: opacity .18s, transform .22s cubic-bezier(.3, 1.5, .5, 1);
}
.cmn-check {
    position: absolute; top: .45rem; right: .45rem;
    width: 21px; height: 21px; border-radius: 50%;
    display: grid; place-items: center;
    font-size: .62rem; font-weight: 900; color: #fff;
    background: var(--k-accent);
    box-shadow: 0 2px 6px rgba(120, 70, 52, .45);
    opacity: 0; transform: scale(.5);
    transition: opacity .18s, transform .22s cubic-bezier(.3, 1.5, .5, 1);
    z-index: 3;
}
.cmn-check.sm { width: 17px; height: 17px; font-size: .54rem; top: .35rem; right: .35rem; }

.cmn-flag {
    position: absolute; top: -7px; left: 50%; transform: translateX(-50%);
    white-space: nowrap;
    font-size: .55rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
    color: #fff; background: var(--k-accent);
    padding: .16rem .5rem; border-radius: 999px;
}
.cmn-flag.out { background: #A99A8E; }


/* ---------- 01 · purpose tiles ---------- */
.cmn-tiles { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: .5rem; }
.cmn-tile {
    position: relative; display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: .5rem;
    padding: .95rem .4rem .8rem; min-height: 92px; text-align: center;
    background: var(--k-card); border: 1px solid var(--k-line);
    border-radius: 7px; cursor: pointer;
    transition: border-color .18s, background .18s, transform .18s, box-shadow .18s;
}
.cmn-tile:hover { border-color: #DCC0B4; transform: translateY(-2px); box-shadow: 0 6px 14px -8px rgba(90, 58, 44, .3); }
.cmn-tile:has(input:checked) {
    background: var(--k-accent-soft); border-color: #E0B9A8;
    box-shadow: inset 0 0 0 1px #E0B9A8;
}
.cmn-tile:has(input:focus-visible) { outline: 2px solid var(--k-accent); outline-offset: 2px; }
.cmn-tile-ico { color: var(--k-ink-2); }
.cmn-tile-ico svg { width: 21px; height: 21px; display: block; }
.cmn-tile:has(input:checked) .cmn-tile-ico { color: var(--k-deep); }
.cmn-tile-name {
    font-size: .68rem; font-weight: 700; line-height: 1.25; color: var(--k-ink-2);
    letter-spacing: .01em;
}
.cmn-tile:has(input:checked) .cmn-tile-name { color: var(--k-deep); }


/* ---------- 02 · format ---------- */
.cmn-formats { display: grid; grid-template-columns: 1fr 1fr; gap: .9rem; }
.cmn-format {
    position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr);
    gap: 1rem; align-items: center;
    padding: 1rem 1.1rem;
    background: var(--k-card); border: 1px solid var(--k-line);
    border-radius: 8px; cursor: pointer;
    transition: border-color .18s, box-shadow .18s, transform .18s;
}
.cmn-format:hover { border-color: #DCC0B4; transform: translateY(-2px); box-shadow: 0 8px 18px -10px rgba(90, 58, 44, .32); }
.cmn-format:has(input:checked) { border-color: var(--k-accent); box-shadow: inset 0 0 0 1px var(--k-accent); }
.cmn-format:has(input:checked) .cmn-radio { border-color: var(--k-accent); }
.cmn-format:has(input:checked) .cmn-radio::after { opacity: 1; transform: scale(1); }
.cmn-format:has(input:focus-visible) { outline: 2px solid var(--k-accent); outline-offset: 2px; }

.cmn-format-media {
    position: relative; display: grid; place-items: center;
    width: 116px; height: 96px; flex: none;
    border-radius: 6px;
    background: radial-gradient(70% 60% at 50% 30%, #FFFCFA, #F2E9E2);
    border: 1px solid var(--k-line-soft);
}
.cmn-eg {
    position: absolute; left: 50%; bottom: 5px; transform: translateX(-50%);
    font-size: .5rem; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
    color: var(--k-faint);
}

/* The fold plan: the piece laid out flat before it is folded, drawn from
   FormatOption.Panels. */
.cmn-fold { display: flex; height: 58px; filter: drop-shadow(0 5px 9px rgba(74, 45, 26, .26)); }
.cmn-fold .panel {
    position: relative; width: 30px; height: 100%;
    background-image: var(--k-grain), linear-gradient(118deg, #B08A63, #8A6544 52%, #6B4A31);
    background-size: 160px 160px, auto;
    background-blend-mode: soft-light, normal;
    box-shadow: inset 0 0 14px -6px rgba(20, 10, 4, .55), inset 0 1px 0 rgba(255, 235, 210, .22);
}
.cmn-fold .panel + .panel { border-left: 1px dashed rgba(255, 240, 220, .45); }
.cmn-fold .panel + .panel::before {
    content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 8px;
    background: linear-gradient(90deg, rgba(20, 10, 4, .34), transparent);
}
.cmn-fold .panel:first-child { border-radius: 5px 1px 1px 5px; }
.cmn-fold .panel:last-child { border-radius: 1px 6px 6px 1px; }
/* the trifold's wrapping panel is narrower, as it is in the real thing */
.cmn-fold[data-panels="3"] .panel:last-child { width: 21px; }

.cmn-format-name {
    display: block; font-family: var(--k-sans); font-size: .78rem; font-weight: 800;
    letter-spacing: .1em; text-transform: uppercase; color: var(--k-ink);
    margin-bottom: .45rem;
}
.cmn-format-diffs { margin: 0; padding: 0; list-style: none; }
.cmn-format-diffs li {
    position: relative; padding-left: .85rem; margin-bottom: .18rem;
    font-size: .8rem; color: var(--k-ink-2); line-height: 1.45;
}
.cmn-format-diffs li::before {
    content: "•"; position: absolute; left: 0; color: var(--k-accent);
}
.cmn-format-blurb {
    display: block; margin-top: .55rem; font-size: .74rem; line-height: 1.5;
    color: var(--k-muted);
}


/* ---------- 03 · size ----------
   --cmn-in is inches → pixels, set on the container. Every rectangle is its
   real dimensions times that one number, so the five are in true proportion to
   each other and stay that way if the sizes change. */
/* Sized in tracks rather than fractions: the shop currently offers two, and two
   tiles stretched across a full-width row look like a mistake. Tracks cap their
   width and stay left-aligned, and the row still wraps cleanly if she adds more. */
.cmn-sizes {
    display: grid; gap: .6rem;
    grid-template-columns: repeat(auto-fill, minmax(158px, 210px));
    justify-content: start;
}
.cmn-size {
    position: relative; display: flex; flex-direction: column; align-items: center;
    padding: .9rem .5rem .8rem;
    background: var(--k-card); border: 1px solid var(--k-line);
    border-radius: 7px; cursor: pointer; text-align: center;
    transition: border-color .18s, box-shadow .18s, transform .18s;
}
.cmn-size:hover { border-color: #DCC0B4; transform: translateY(-2px); box-shadow: 0 8px 16px -10px rgba(90, 58, 44, .3); }
.cmn-size:has(input:checked) { border-color: var(--k-accent); box-shadow: inset 0 0 0 1px var(--k-accent); }
.cmn-size:has(input:checked) .cmn-radio { border-color: var(--k-accent); }
.cmn-size:has(input:checked) .cmn-radio::after { opacity: 1; transform: scale(1); }
.cmn-size:has(input:focus-visible) { outline: 2px solid var(--k-accent); outline-offset: 2px; }

.cmn-size-stage {
    display: flex; align-items: flex-end; justify-content: center;
    /* the tallest size sets the stage, so every card shares one baseline */
    height: calc(var(--cmn-in) * var(--cmn-tallest));
    margin-bottom: .6rem;
}
.cmn-size-book {
    position: relative;
    width: calc(var(--cmn-in) * var(--w));
    height: calc(var(--cmn-in) * var(--h));
    border-radius: 2px 5px 5px 2px;
    background-image: var(--k-grain), linear-gradient(118deg, #D9A99A, #C58A7A 52%, #A46E5F);
    background-size: 160px 160px, auto;
    background-blend-mode: soft-light, normal;
    box-shadow: inset 0 0 12px -5px rgba(60, 26, 16, .5), 0 5px 10px -5px rgba(90, 50, 36, .45);
}
/* Her own photograph, standing in the drawing's footprint. Cropped rather than
   letterboxed: the row promises the sizes are shown to scale, and a photo that
   shrinks to fit its own aspect ratio would quietly break that promise. */
.cmn-size-photo {
    width: calc(var(--cmn-in) * var(--w));
    height: calc(var(--cmn-in) * var(--h));
    object-fit: cover;
    border-radius: 2px 5px 5px 2px;
    display: block;
    box-shadow: 0 5px 10px -5px rgba(90, 50, 36, .45);
}
.cmn-size-book .spine {
    position: absolute; top: 0; bottom: 0; left: 3px; width: 1.5px; border-radius: 2px;
    background: linear-gradient(rgba(50, 22, 12, .34), rgba(50, 22, 12, .1));
}
/* the closure strap, so the thumbnail reads as one of ours */
.cmn-size-book::after {
    content: ""; position: absolute; top: 50%; right: -2px; width: 26%; height: 3px;
    transform: translateY(-50%); border-radius: 2px;
    background: linear-gradient(90deg, #E7C6B8, #C08E7C);
    box-shadow: 0 1px 2px rgba(60, 26, 16, .35);
}
.cmn-size-name {
    font-size: .7rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
    color: var(--k-ink);
}
.cmn-size-dims {
    font-size: .68rem; color: var(--k-muted); margin-top: .12rem;
    font-variant-numeric: tabular-nums;
}


/* ---------- 04 · leather ----------
   auto-fill, because leathers are a shelf the owner adds to — a fixed column
   count would break the moment she takes delivery of a ninth hide. */
.cmn-leathers {
    display: grid; gap: .5rem;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
}
/* A tile that can carry a photograph. The View control has to be a sibling of the
   label rather than a child — a label forwards a press to the control it labels,
   so a button inside one would select the option instead of opening the picture.
   The wrapper gives it somewhere to sit, and takes the hover lift so the control
   travels with the tile instead of being left behind by it. */
.cmn-shot {
    position: relative; display: flex; flex-direction: column;
    transition: transform .18s ease;
}
.cmn-shot:hover { transform: translateY(-2px); }
.cmn-shot:has(.is-out):hover { transform: none; }
.cmn-shot > label { flex: 1; min-width: 0; }

/* The control sits in its own strip above the tile rather than floating over the
   picture — the whole point of the photograph is to be looked at. The strip is
   rendered on every tile, empty where there is nothing to view, so the images
   across a row still line up. */
.cmn-viewbar {
    display: flex; justify-content: center; align-items: flex-end;
    min-height: 20px; margin-bottom: 3px;
}
.cmn-view { opacity: .78; transition: opacity .16s ease, background .16s ease, transform .16s ease; }
.cmn-shot:hover .cmn-view, .cmn-view:focus-visible { opacity: 1; }
/* No hover on touch, so it is simply always legible there. */
@media (hover: none) { .cmn-view { opacity: 1; } }

/* Her own photograph, wherever one has been uploaded. Each of these replaces a
   drawn placeholder, so it takes the same footprint the drawing had — otherwise
   uploading one picture would reflow a whole row. */
.cmn-tile-photo {
    width: 34px; height: 34px; object-fit: cover; border-radius: 5px; display: block;
}
.cmn-media-photo {
    max-width: 100%; max-height: 100%; width: auto; height: auto;
    object-fit: contain; display: block; border-radius: 5px;
}
.cmn-format-media .cmn-media-photo { max-height: 78px; }
.cmn-spread-photo {
    width: 78px; height: 60px; object-fit: cover; border-radius: 4px;
    margin-bottom: .55rem; display: block;
    box-shadow: 0 3px 6px rgba(90, 58, 44, .2);
}

.cmn-leather {
    position: relative; display: flex; flex-direction: column; align-items: center;
    cursor: pointer; text-align: center;
    padding: 0 0 .1rem;
    border-radius: 7px;
}
.cmn-leather:has(input:focus-visible) { outline: 2px solid var(--k-accent); outline-offset: 3px; }

.cmn-leather-media {
    position: relative; display: block; width: 100%; aspect-ratio: 1 / .82;
    border-radius: 6px; overflow: hidden;
    border: 1px solid var(--k-line);
    box-shadow: 0 2px 6px -3px rgba(70, 40, 28, .3);
    transition: box-shadow .18s, border-color .18s;
}
.cmn-leather:has(input:checked) .cmn-leather-media {
    border-color: var(--k-accent);
    box-shadow: 0 0 0 2px var(--k-accent), 0 6px 14px -6px rgba(120, 70, 52, .5);
}
.cmn-leather:has(input:checked) .cmn-check { opacity: 1; transform: scale(1); }
.cmn-leather-media img { width: 100%; height: 100%; object-fit: cover; display: block; }

.cmn-leather-name {
    margin-top: .45rem; font-size: .68rem; font-weight: 700; color: var(--k-ink);
    line-height: 1.25;
}
.cmn-leather-type {
    font-size: .58rem; letter-spacing: .06em; text-transform: uppercase;
    color: var(--k-faint); margin-top: .06rem;
}
.cmn-leather.is-out { opacity: .5; cursor: not-allowed; }
.cmn-leather.is-out .cmn-leather-media { filter: saturate(.5); }
/* An out-of-stock hide can still be looked at — she may be taking delivery of it
   next month, and that is exactly when someone wants to see it. */
.cmn-shot:has(.is-out) .cmn-view { opacity: 1; }


/* ---------- drawn leather swatches ----------
   No photography of raw hide exists for this shop, and a stock photo of the
   wrong leather is worse than an honest drawing. Each swatch is built from the
   option's own --tone plus a grain pass tuned to how that leather behaves. Set
   LeatherOption.ImageUrl and a photograph replaces all of it. */
.cmn-swatch {
    position: absolute; inset: 0; display: block;
    --t-hi: color-mix(in srgb, var(--tone) 62%, #FFF0DC);
    --t-lo: color-mix(in srgb, var(--tone) 62%, #1B0F09);
    --t-deep: color-mix(in srgb, var(--tone) 38%, #150B06);
    background-image:
        var(--k-grain),
        radial-gradient(120% 100% at 26% 18%, color-mix(in srgb, var(--t-hi) 72%, #fff) 0%, transparent 56%),
        linear-gradient(122deg, var(--t-hi) 0%, var(--tone) 48%, var(--t-lo) 100%);
    background-size: 160px 160px, auto, auto;
    background-blend-mode: soft-light, normal, normal;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08), inset 0 0 26px -10px rgba(30, 14, 6, .5);
}
/* a raking sheen across every hide, strength varied per type below */
.cmn-swatch::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(118deg, rgba(255, 255, 255, .24) 0%, transparent 36%);
    opacity: var(--sheen, .8);
}

/* Crazy horse: hot wax, so the colour lifts wherever the hide has flexed —
   big soft light patches over a dark ground, and a waxy specular on top. */
.cmn-swatch[data-swatch="crazy-horse"] {
    background-image:
        var(--k-grain-coarse),
        radial-gradient(48% 58% at 24% 30%, color-mix(in srgb, var(--t-hi) 92%, #FFE9CD) 0%, transparent 64%),
        radial-gradient(38% 46% at 74% 68%, color-mix(in srgb, var(--t-hi) 76%, #FFDFBB) 0%, transparent 68%),
        linear-gradient(128deg, var(--t-lo) 0%, var(--tone) 46%, var(--t-deep) 100%);
    background-size: 240px 240px, auto, auto, auto;
    background-blend-mode: soft-light, screen, screen, normal;
    --sheen: 1;
}
/* Full grain: even tone, real pores, a quiet directional light. */
.cmn-swatch[data-swatch="full-grain"] {
    background-image:
        var(--k-grain),
        radial-gradient(circle at 50% 50%, rgba(20, 10, 4, .15) 0 .9px, transparent 1.7px),
        radial-gradient(120% 96% at 28% 20%, color-mix(in srgb, var(--t-hi) 72%, #fff) 0%, transparent 54%),
        linear-gradient(122deg, var(--t-hi) 0%, var(--tone) 48%, var(--t-lo) 100%);
    background-size: 160px 160px, 7px 7px, auto, auto;
    background-blend-mode: soft-light, normal, normal, normal;
    --sheen: .7;
}
/* Pebbled: milled until the grain draws up. A staggered pair of dot layers
   reads as a pebble field far more cheaply than a tiled image would. */
.cmn-swatch[data-swatch="pebbled"] {
    background-image:
        radial-gradient(circle at 50% 42%, rgba(255, 240, 220, .26) 0 2.6px, transparent 4px),
        radial-gradient(circle at 50% 58%, rgba(24, 12, 5, .32) 0 3px, transparent 4.4px),
        var(--k-grain),
        linear-gradient(122deg, var(--t-hi) 0%, var(--tone) 50%, var(--t-lo) 100%);
    background-size: 11px 11px, 11px 11px, 160px 160px, auto;
    background-position: 0 0, 0 1px, 0 0, 0 0;
    background-blend-mode: normal, normal, soft-light, normal;
    --sheen: .48;
}
/* Suede: nap, not surface. No specular at all, coarse fibre, desaturated. */
.cmn-swatch[data-swatch="suede"] {
    background-image:
        var(--k-grain-coarse),
        var(--k-grain-fine),
        radial-gradient(130% 108% at 32% 24%, color-mix(in srgb, var(--t-hi) 58%, #fff) 0%, transparent 64%),
        linear-gradient(122deg, var(--t-hi) 0%, var(--tone) 52%, var(--t-lo) 100%);
    background-size: 240px 240px, 120px 120px, auto, auto;
    background-blend-mode: soft-light, soft-light, normal, normal;
    filter: saturate(.88) contrast(.96);
    --sheen: .08;
}
/* Vegetable tanned: pale, bare, almost no dye — the one hide that will
   visibly change with use. */
.cmn-swatch[data-swatch="veg-tan"] {
    background-image:
        var(--k-grain-fine),
        radial-gradient(circle at 50% 50%, rgba(90, 56, 22, .1) 0 .8px, transparent 1.5px),
        radial-gradient(126% 100% at 30% 16%, color-mix(in srgb, var(--t-hi) 88%, #FFF6E6) 0%, transparent 58%),
        linear-gradient(122deg, color-mix(in srgb, var(--t-hi) 92%, #FFF3E2) 0%, var(--tone) 56%, var(--t-lo) 100%);
    background-size: 120px 120px, 7px 7px, auto, auto;
    background-blend-mode: soft-light, normal, normal, normal;
    --sheen: .55;
}


/* ---------- 05 · hardware ----------
   The metal on the journal. Same tile as a leather so the three colour rows
   read as one run of decisions, but the swatch is built from a finish rather
   than a grain: the colour is the row's own --tone, and the finish only decides
   how it catches the light. That split is what lets a fifth metal be a name and
   a hex from the admin instead of a deploy. */
.cmn-metals {
    display: grid; gap: .5rem;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
}
.cmn-metal {
    position: relative; display: flex; flex-direction: column; align-items: center;
    cursor: pointer; text-align: center; padding: 0 0 .1rem; border-radius: 7px;
}
.cmn-metal:has(input:focus-visible) { outline: 2px solid var(--k-accent); outline-offset: 3px; }
.cmn-metal-media {
    position: relative; display: block; width: 100%; aspect-ratio: 1 / .82;
    border-radius: 6px; overflow: hidden;
    border: 1px solid var(--k-line);
    box-shadow: 0 2px 6px -3px rgba(70, 40, 28, .3);
    transition: box-shadow .18s, border-color .18s;
}
.cmn-metal:has(input:checked) .cmn-metal-media {
    border-color: var(--k-accent);
    box-shadow: 0 0 0 2px var(--k-accent), 0 6px 14px -6px rgba(120, 70, 52, .5);
}
.cmn-metal:has(input:checked) .cmn-check { opacity: 1; transform: scale(1); }
.cmn-metal-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cmn-metal-name {
    margin-top: .45rem; font-size: .68rem; font-weight: 700; color: var(--k-ink);
    line-height: 1.25;
}
.cmn-metal.is-out { opacity: .5; cursor: not-allowed; }
.cmn-metal.is-out .cmn-metal-media { filter: saturate(.5); }

/* Metal reads as metal because of the banding, not the colour — a flat fill of
   the same hex looks like paint. Two bright bands and one dark one across a
   diagonal is the cheapest thing that convinces. */
.cmn-metal-swatch {
    position: absolute; inset: 0; display: block;
    --m-hi: color-mix(in srgb, var(--tone) 40%, #FFFDF6);
    --m-lo: color-mix(in srgb, var(--tone) 55%, #14100B);
    background-image: linear-gradient(
        128deg,
        var(--m-lo) 0%, var(--tone) 18%, var(--m-hi) 34%,
        var(--tone) 48%, var(--m-lo) 62%, var(--tone) 76%,
        var(--m-hi) 88%, var(--tone) 100%);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .1), inset 0 0 22px -8px rgba(20, 14, 8, .55);
}
.cmn-metal-swatch::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(118deg, rgba(255, 255, 255, .5) 0%, transparent 30%);
    opacity: var(--gloss, 1);
}

/* Brushed: fine parallel striations, and the banding pulled right back. */
.cmn-metal-swatch[data-finish="brushed"] {
    background-image:
        repeating-linear-gradient(96deg,
            rgba(255, 255, 255, .13) 0 1px, transparent 1px 3px),
        linear-gradient(128deg, var(--m-lo) 0%, var(--tone) 40%, var(--m-hi) 62%, var(--tone) 100%);
    --gloss: .35;
}
/* Matte: no specular at all, just a soft light from above. Black hardware is
   this — a mirrored black swatch reads as patent leather, not metal. */
.cmn-metal-swatch[data-finish="matte"] {
    background-image:
        var(--k-grain-fine),
        linear-gradient(160deg, color-mix(in srgb, var(--tone) 78%, #fff) 0%, var(--tone) 55%, var(--m-lo) 100%);
    background-size: 120px 120px, auto;
    background-blend-mode: soft-light, normal;
    --gloss: 0;
}
/* Antiqued: darkened into the corners with the light held in the middle, the
   way a bronze that has been rubbed back actually sits. */
.cmn-metal-swatch[data-finish="antiqued"] {
    background-image:
        var(--k-grain),
        radial-gradient(72% 68% at 42% 38%, color-mix(in srgb, var(--m-hi) 88%, #FFE9C8) 0%, transparent 70%),
        linear-gradient(128deg, var(--m-lo) 0%, var(--tone) 46%, var(--m-lo) 100%);
    background-size: 160px 160px, auto, auto;
    background-blend-mode: soft-light, screen, normal;
    --gloss: .45;
}


/* ---------- 06 · elastic ----------
   A cord, drawn as a cord: the band lies across a paper ground rather than
   filling the tile, because what the customer is choosing is a strap they will
   see against the journal, not a field of colour. */
.cmn-cords {
    display: grid; gap: .5rem;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
}
.cmn-cord {
    position: relative; display: flex; flex-direction: column; align-items: center;
    cursor: pointer; text-align: center; padding: 0 0 .1rem; border-radius: 7px;
}
.cmn-cord:has(input:focus-visible) { outline: 2px solid var(--k-accent); outline-offset: 3px; }
.cmn-cord-media {
    position: relative; display: block; width: 100%; aspect-ratio: 1 / .82;
    border-radius: 6px; overflow: hidden;
    border: 1px solid var(--k-line);
    background: linear-gradient(160deg, #FFFDFB 0%, #F4EAE4 100%);
    box-shadow: 0 2px 6px -3px rgba(70, 40, 28, .3);
    transition: box-shadow .18s, border-color .18s;
}
.cmn-cord:has(input:checked) .cmn-cord-media {
    border-color: var(--k-accent);
    box-shadow: 0 0 0 2px var(--k-accent), 0 6px 14px -6px rgba(120, 70, 52, .5);
}
.cmn-cord:has(input:checked) .cmn-check { opacity: 1; transform: scale(1); }
.cmn-cord-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cmn-cord-name {
    margin-top: .45rem; font-size: .68rem; font-weight: 700; color: var(--k-ink);
    line-height: 1.25;
}
.cmn-cord.is-out { opacity: .5; cursor: not-allowed; }
.cmn-cord.is-out .cmn-cord-media { filter: saturate(.5); }

/* The braid: a tight diagonal weave over the tone, rounded at the ends and
   dropped on a shadow so it sits on the paper rather than in it. */
.cmn-cord-swatch {
    position: absolute; left: 0; right: 0; top: 50%;
    height: 34%; transform: translateY(-50%);
    background-image:
        repeating-linear-gradient(58deg,
            rgba(255, 255, 255, .22) 0 2px,
            transparent 2px 4px,
            rgba(0, 0, 0, .14) 4px 6px,
            transparent 6px 8px),
        linear-gradient(180deg,
            color-mix(in srgb, var(--tone) 72%, #fff) 0%,
            var(--tone) 46%,
            color-mix(in srgb, var(--tone) 70%, #120C08) 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .3),
        0 3px 7px -3px rgba(60, 34, 22, .55);
}


/* ---------- 07 · interior pages ---------- */
/* auto-fill rather than a fixed count: the rulings on offer are hers to change,
   and a hard-coded five left two dead columns the day two came off the shelf. */
.cmn-pages {
    display: grid; gap: .5rem;
    grid-template-columns: repeat(auto-fill, minmax(122px, 1fr));
}
.cmn-page {
    position: relative; display: flex; flex-direction: column; align-items: center;
    padding: .9rem .5rem .8rem;
    background: var(--k-card); border: 1px solid var(--k-line);
    border-radius: 7px; cursor: pointer; text-align: center;
    transition: border-color .18s, box-shadow .18s, transform .18s;
}
.cmn-page:hover { border-color: #DCC0B4; transform: translateY(-2px); box-shadow: 0 8px 16px -10px rgba(90, 58, 44, .3); }
.cmn-page:has(input:checked) { border-color: var(--k-accent); box-shadow: inset 0 0 0 1px var(--k-accent); }
.cmn-page:has(input:checked) .cmn-radio { border-color: var(--k-accent); }
.cmn-page:has(input:checked) .cmn-radio::after { opacity: 1; transform: scale(1); }
.cmn-page:has(input:focus-visible) { outline: 2px solid var(--k-accent); outline-offset: 2px; }

/* An open spread rather than a single page — two leaves with a gutter between,
   which is how you actually see a ruling. */
.cmn-spread {
    display: flex; gap: 2px; width: 78px; height: 60px; margin-bottom: .55rem;
    filter: drop-shadow(0 3px 6px rgba(90, 58, 44, .2));
}
.cmn-spread .leaf {
    flex: 1; background-color: #FEFBF3;
    border: 1px solid #EADFC9;
    background-repeat: no-repeat;
    background-position: 5px 6px;
    background-size: calc(100% - 10px) calc(100% - 12px);
}
.cmn-spread .leaf:first-child { border-radius: 4px 1px 1px 4px; box-shadow: inset -5px 0 7px -6px rgba(120, 80, 40, .6); }
.cmn-spread .leaf:last-child { border-radius: 1px 4px 4px 1px; box-shadow: inset 5px 0 7px -6px rgba(120, 80, 40, .6); }

.cmn-spread[data-rule="lined"] .leaf {
    background-image: repeating-linear-gradient(to bottom, transparent 0 5px, rgba(150, 120, 80, .42) 5px 6px);
}
.cmn-spread[data-rule="dot"] .leaf {
    background-image: radial-gradient(circle, rgba(150, 120, 80, .5) 0 .8px, transparent 1.2px);
    background-size: 6px 6px;
}
.cmn-spread[data-rule="blank"] .leaf { background-image: none; }
/* planner: a header band and a column of day rules */
.cmn-spread[data-rule="planner"] .leaf {
    background-image:
        linear-gradient(rgba(168, 112, 92, .5), rgba(168, 112, 92, .5)),
        repeating-linear-gradient(to bottom, transparent 0 5px, rgba(150, 120, 80, .34) 5px 6px);
    background-size: calc(100% - 10px) 5px, calc(100% - 10px) calc(100% - 22px);
    background-position: 5px 6px, 5px 16px;
}
/* mixed: lined on the left leaf, dotted on the right */
.cmn-spread[data-rule="mixed"] .leaf:first-child {
    background-image: repeating-linear-gradient(to bottom, transparent 0 5px, rgba(150, 120, 80, .42) 5px 6px);
}
.cmn-spread[data-rule="mixed"] .leaf:last-child {
    background-image: radial-gradient(circle, rgba(150, 120, 80, .5) 0 .8px, transparent 1.2px);
    background-size: 6px 6px;
}

.cmn-page-name {
    font-size: .7rem; font-weight: 700; color: var(--k-ink); line-height: 1.25;
}


/* ---------- 08 · charms, 09 · upgraded charms ----------
   Two shelves, one tile. Both are shelves the owner adds to, so the same
   auto-fill treatment; the upgraded ones are given a little more room because
   they carry a price under the name. */
.cmn-charms {
    display: grid; gap: .5rem;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
}
.cmn-charms.is-upgraded {
    grid-template-columns: repeat(auto-fill, minmax(108px, 1fr));
}
.cmn-charm {
    position: relative; display: flex; flex-direction: column; align-items: center; gap: .45rem;
    padding: .85rem .4rem .75rem;
    background: var(--k-card); border: 1px solid var(--k-line);
    border-radius: 7px; cursor: pointer; text-align: center;
    transition: border-color .18s, background .18s, box-shadow .18s, transform .18s;
}
/* No lift here: a charm that carries a photograph sits inside .cmn-shot, which
   takes the lift so the View button travels with it. */
.cmn-charm:hover { border-color: #DCC0B4; box-shadow: 0 8px 16px -10px rgba(90, 58, 44, .3); }
.cmn-charm:has(input:checked) {
    border-color: var(--k-gold);
    background: linear-gradient(to bottom, #FFFDF7, #FBF3E2);
    box-shadow: inset 0 0 0 1px var(--k-gold);
}
.cmn-charm:has(input:checked) .cmn-check { opacity: 1; transform: scale(1); background: var(--k-gold); }
.cmn-charm:has(input:focus-visible) { outline: 2px solid var(--k-accent); outline-offset: 2px; }

.cmn-charm-art {
    display: grid; place-items: center; height: 34px; color: var(--k-gold);
    filter:
        drop-shadow(0 1px 0 rgba(70, 44, 8, .4))
        drop-shadow(0 -.5px 0 rgba(255, 248, 220, .5));
}
.cmn-charm-art svg { width: 28px; height: 28px; display: block; }
/* her own photograph of the charm, when she has uploaded one */
.cmn-charm-art img {
    width: 34px; height: 34px; object-fit: contain; display: block;
}
.cmn-charm.has-photo .cmn-charm-art { filter: drop-shadow(0 2px 3px rgba(60, 44, 20, .3)); }
.cmn-charm-art .glyph {
    font-family: var(--k-serif); font-size: 1.75rem; line-height: 1;
    background: linear-gradient(150deg, #F0DFAE, #B08A3C 46%, #EBD9A0 64%, #7E5C1B);
    -webkit-background-clip: text; background-clip: text; color: transparent;
    text-rendering: geometricPrecision;
}
/* "None" is a real choice, not an absence — but it should not glitter. */
.cmn-charm-art.is-none { color: var(--k-faint); filter: none; }

.cmn-charm-name { font-size: .66rem; font-weight: 700; color: var(--k-ink-2); line-height: 1.25; }
.cmn-charm.is-out { opacity: .45; cursor: not-allowed; }
.cmn-charm.is-out:hover { box-shadow: none; }

/* What a charm adds. Always on the upgraded shelf — it is the reason that section
   exists. On the basic shelf the commission page leaves it off, because one charm
   there is included and the rest are pennies beside the journal; the ready-to-ship
   page turns it on, because nothing is included there and every tick is charged. */
.cmn-charm-price {
    font-size: .64rem; font-weight: 800; letter-spacing: .01em;
    color: var(--k-accent);
    font-variant-numeric: tabular-nums;
}

/* the custom-charm request, folded away until it is wanted */
/* "One charm is included" — stated at the tiles, not only in the estimate.
   Someone who reads no further than the shelf should still know the first one
   costs nothing. */
.cmn-included {
    display: flex; align-items: flex-start; gap: .55rem;
    margin: 0 0 .85rem; padding: .6rem .8rem;
    border: 1px solid var(--k-accent-soft); border-radius: 8px;
    background: #FCF4F0;
    font-size: .78rem; line-height: 1.45; color: var(--k-ink-2);
}
.cmn-included b { color: var(--k-ink); }
.cmn-included-mark {
    flex: none; width: 18px; height: 18px; margin-top: .05rem;
    border-radius: 50%; display: grid; place-items: center;
    background: var(--k-accent); color: #fff;
    font-size: .56rem; font-weight: 900;
}

/* The upgraded charms used to be a single "tell me more" checkbox here, with no
   price to put on a tile. They are a shelf of their own now — real pieces at real
   prices, section 09 — so the checkbox and its styles are gone. */

.cmn-custom {
    margin-top: .8rem; border: 1px dashed var(--k-line);
    border-radius: 8px; background: #FDF9F7;
}
.cmn-custom summary {
    display: flex; align-items: center; justify-content: space-between; gap: 1rem;
    padding: .7rem 1rem; cursor: pointer; list-style: none;
    font-size: .8rem; font-weight: 700; color: var(--k-accent);
}
.cmn-custom summary::-webkit-details-marker { display: none; }
.cmn-custom summary:focus-visible { outline: 2px solid var(--k-accent); outline-offset: -2px; border-radius: 8px; }
.cmn-custom .chev { transition: transform .2s ease; }
.cmn-custom[open] .chev { transform: rotate(180deg); }
.cmn-custom-body { padding: 0 1rem 1rem; }
.cmn-custom-body .cmn-row-note { margin-top: 0; margin-bottom: .7rem; }


/* ==================== UPLOADS ==================== */
.cmn-drop { position: relative; }
.cmn-drop-input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }
.cmn-drop-face {
    display: flex; flex-direction: column; align-items: center; text-align: center; gap: .3rem;
    padding: 1.5rem 1.2rem;
    border: 1.5px dashed #DBC6BB; border-radius: 8px;
    background: #FDFAF8; cursor: pointer;
    transition: border-color .18s, background .18s;
}
.cmn-drop.is-lg .cmn-drop-face { padding: 2.4rem 1.4rem; }
.cmn-drop-face:hover { border-color: var(--k-accent); background: #FDF6F2; }
.cmn-drop.is-over .cmn-drop-face { border-color: var(--k-accent); background: var(--k-accent-soft); }
.cmn-drop:has(.cmn-drop-input:focus-visible) .cmn-drop-face { outline: 2px solid var(--k-accent); outline-offset: 2px; }

.cmn-drop-icon { color: var(--k-accent); }
.cmn-drop-icon svg { width: 26px; height: 26px; display: block; }
.cmn-drop.is-lg .cmn-drop-icon svg { width: 30px; height: 30px; }
.cmn-drop-title { font-size: .88rem; font-weight: 700; color: var(--k-ink); margin-top: .2rem; }
.cmn-drop-hint { font-size: .76rem; color: var(--k-muted); max-width: 62ch; line-height: 1.5; }
.cmn-drop-cta {
    margin-top: .6rem; padding: .45rem 1.1rem; border-radius: 5px;
    background: var(--k-deep); color: #FBF4EF;
    font-size: .74rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
    transition: background .18s;
}
.cmn-drop-face:hover .cmn-drop-cta { background: var(--k-accent); }
.cmn-drop-or { font-size: .7rem; color: var(--k-faint); font-style: italic; }

.cmn-thumbs {
    list-style: none; margin: 0; padding: 0;
    display: grid; gap: .5rem; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
}
.cmn-thumbs:not(:empty) { margin-top: .7rem; }
.cmn-thumb {
    position: relative; aspect-ratio: 1; border-radius: 6px; overflow: hidden;
    background: #F1E6DF; border: 1px solid var(--k-line);
    animation: cmn-pop .26s cubic-bezier(.3, 1.3, .5, 1) both;
}
@keyframes cmn-pop { from { opacity: 0; transform: scale(.9); } to { opacity: 1; transform: scale(1); } }
.cmn-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cmn-thumb-name {
    position: absolute; left: 0; right: 0; bottom: 0; padding: .45rem .4rem .3rem;
    font-size: .56rem; font-weight: 700; color: #FFF3E9;
    background: linear-gradient(to top, rgba(40, 22, 14, .82), transparent);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Sits over the filename strip at the foot of the thumbnail, opposite nothing —
   the remove button is at the top, so the two never crowd each other. */
.cmn-thumb-view {
    position: absolute; left: .25rem; bottom: .25rem; z-index: 2;
    opacity: 0; transition: opacity .16s ease;
}
.cmn-thumb:hover .cmn-thumb-view,
.cmn-thumb-view:focus-visible { opacity: 1; }
/* Touch has no hover, so it is always there on a coarse pointer. */
@media (hover: none) { .cmn-thumb-view { opacity: 1; } }

.cmn-thumb-remove {
    position: absolute; top: .25rem; right: .25rem;
    width: 20px; height: 20px; border-radius: 50%; border: none;
    background: rgba(40, 22, 14, .62); color: #fff;
    font-size: .75rem; line-height: 1; cursor: pointer;
    display: grid; place-items: center;
    transition: background .16s, transform .16s;
}
.cmn-thumb-remove:hover { background: #8A4433; transform: scale(1.1); }
.cmn-thumb-remove:focus-visible { outline: 2px solid #fff; outline-offset: 1px; }

.cmn-drop-err {
    margin: .6rem 0 0; padding: .6rem .9rem; border-radius: 6px;
    background: #FBEAE4; border: 1px solid #E9C2B4; color: #8A4433;
    font-size: .78rem; font-weight: 600; white-space: pre-line;
}


/* ==================== FIELDS ==================== */
.cmn-field { display: block; position: relative; }
.cmn-field > span:first-child {
    display: block; margin-bottom: .35rem;
    font-size: .7rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
    color: var(--k-ink-2);
}
.cmn-field > span:first-child i {
    font-style: normal; font-weight: 700; font-size: .62rem;
    color: var(--k-faint); margin-left: .3rem; letter-spacing: .04em;
}
.cmn-field input, .cmn-field textarea {
    width: 100%; font-family: var(--k-sans); font-size: .92rem; color: var(--k-ink);
    background: var(--k-card); border: 1px solid var(--k-line); border-radius: 7px;
    padding: .7rem .9rem; line-height: 1.6;
    transition: border-color .16s, box-shadow .16s;
}
.cmn-field textarea { resize: vertical; min-height: 70px; }
.cmn-field input::placeholder, .cmn-field textarea::placeholder { color: #C3B1A5; }
.cmn-field input:focus, .cmn-field textarea:focus {
    outline: none; border-color: var(--k-accent);
    box-shadow: 0 0 0 3px rgba(168, 112, 92, .15);
}
.cmn-field input.invalid, .cmn-field textarea.invalid {
    border-color: #D08B78; box-shadow: 0 0 0 3px rgba(208, 139, 120, .16);
}
.cmn-field-lg textarea { min-height: 168px; padding: .95rem 1.05rem 1.9rem; line-height: 1.7; }
.cmn-count {
    position: absolute; right: .8rem; bottom: .6rem;
    font-size: .68rem; color: var(--k-faint); font-variant-numeric: tabular-nums;
    pointer-events: none;
}
.cmn-count.full { color: #B26B55; font-weight: 700; }
.cmn-err { display: block; margin-top: .3rem; font-size: .74rem; color: #B24B33; font-weight: 600; }
.cmn-err:empty { display: none; }

.cmn-prompts { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .7rem; }
.cmn-prompt {
    font-family: var(--k-sans); font-size: .74rem; font-weight: 600;
    color: var(--k-ink-2); background: var(--k-card);
    border: 1px solid var(--k-line); border-radius: 999px;
    padding: .35rem .85rem; cursor: pointer;
    transition: border-color .16s, color .16s, transform .16s;
}
.cmn-prompt:hover { border-color: var(--k-accent); color: var(--k-accent); transform: translateY(-1px); }
.cmn-prompt:focus-visible { outline: 2px solid var(--k-accent); outline-offset: 2px; }
.cmn-prompt.used { opacity: .42; }

.cmn-details { display: grid; grid-template-columns: repeat(3, 1fr); gap: .9rem; }


/* ==================== THE BRIEF ==================== */
/* The panel follows the reader down the form.

   `align-self: stretch` is the load-bearing line: .cmn-layout sets
   `align-items: start`, which makes every grid item exactly as tall as its own
   content — and a sticky element cannot travel outside its containing block, so
   with a content-height parent it has nowhere to go and never moves. Stretching
   the column to the full row height gives it the whole form to travel down. */
.cmn-brief { position: relative; align-self: stretch; }
.cmn-brief-inner {
    position: sticky; top: 90px;
    padding: 1.7rem 1.6rem 1.5rem;
    background: linear-gradient(to bottom, var(--k-panel-2), var(--k-panel));
    border: 1px solid #E5D2C9; border-radius: 4px;
    box-shadow: 0 18px 40px -28px rgba(80, 48, 34, .5);
    /* Never let the panel outgrow the viewport: pinned taller than the screen it
       would hide its own submit button, which is the one thing it exists for. */
    max-height: calc(100vh - 110px); overflow-y: auto;
    scrollbar-width: thin;
}

.cmn-brief-title {
    font-family: var(--k-sans); font-size: .72rem; font-weight: 800;
    letter-spacing: .18em; text-transform: uppercase; color: var(--k-deep);
    text-align: center; margin: 0;
}
.cmn-rule {
    display: block; text-align: center; color: #CDB4A6;
    font-size: .6rem; letter-spacing: .5em; margin: .5rem 0 1.1rem;
}
.cmn-rule::before, .cmn-rule::after { content: "———"; letter-spacing: -.1em; opacity: .55; }

.cmn-brief-list { margin: 0; padding: 0; }
.cmn-brief-row {
    display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
    gap: .75rem; align-items: center;
    padding: .55rem 0;
}
.cmn-brief-ico { color: var(--k-accent); opacity: .8; }
.cmn-brief-ico svg { width: 19px; height: 19px; display: block; }
/* Once a choice has a photograph, the brief shows the thing itself rather than a
   generic icon — the panel is the closest thing this page has to a basket, and a
   basket should show you what is in it. The icon slot simply grows to fit. */
.cmn-brief-row.has-photo .cmn-brief-ico {
    width: 34px; height: 34px; opacity: 1;
    border-radius: 5px; overflow: hidden;
    border: 1px solid #E0CEC4; background: #fff;
}
.cmn-brief-ico img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Charms are the one row that can hold several, so their pictures sit on their
   own line under the names instead of in the icon slot. */
.cmn-brief-charms {
    display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .35rem;
}
.cmn-brief-charms img {
    width: 30px; height: 30px; object-fit: cover; display: block;
    border-radius: 5px; border: 1px solid #E0CEC4; background: #fff;
}
.cmn-brief-charms:empty { display: none; }
.cmn-brief-row dt {
    font-size: .78rem; font-weight: 700; color: var(--k-ink); line-height: 1.3;
}
.cmn-brief-row dd {
    margin: 0; font-size: .76rem; color: var(--k-ink-2); line-height: 1.35;
    overflow-wrap: anywhere;
}
.cmn-brief-row dd.empty { color: var(--k-faint); font-style: italic; }
.cmn-edit {
    font-size: .7rem; font-weight: 700; color: var(--k-accent);
    padding: .2rem .3rem; border-radius: 4px;
}
.cmn-edit:hover { color: var(--k-deep); text-decoration: underline; }
.cmn-edit:focus-visible { outline: 2px solid var(--k-accent); outline-offset: 1px; }
/* the row that just changed gets a moment's attention, then lets go */
.cmn-brief-row.just-set dd { animation: cmn-flash .9s ease; }
@keyframes cmn-flash {
    0% { color: var(--k-accent); }
    100% { color: var(--k-ink-2); }
}

.cmn-estimate { list-style: none; margin: 0 0 1.1rem; padding: 0; }
.cmn-estimate li {
    display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
    padding: .32rem 0; font-size: .8rem; color: var(--k-ink-2);
}
.cmn-estimate b { font-weight: 700; color: var(--k-ink); font-variant-numeric: tabular-nums; }
.cmn-estimate li.is-new { animation: cmn-slide .3s ease both; }
/* A line with words where the figure goes — the included charm, an upgraded one
   the maker prices by hand. Set apart from the numbers so the column of figures
   still scans as a column. */
.cmn-estimate b.note {
    font-size: .68rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
    color: var(--k-accent); white-space: nowrap;
}
@keyframes cmn-slide { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: none; } }

.cmn-total { text-align: center; padding-top: 1rem; border-top: 1px solid #E1CEC4; }
.cmn-total-label {
    display: block; font-size: .68rem; font-weight: 800;
    letter-spacing: .18em; text-transform: uppercase; color: var(--k-ink-2);
    margin-bottom: .3rem;
}
.cmn-total strong {
    display: block; font-family: var(--k-serif); font-weight: 400;
    font-size: 2.7rem; line-height: 1.05; color: var(--k-deep);
    font-variant-numeric: tabular-nums;
}
.cmn-total em {
    display: block; margin-top: .35rem;
    font-size: .68rem; font-style: italic; color: var(--k-muted);
}

.cmn-submit {
    width: 100%; margin-top: 1.3rem;
    font-family: var(--k-sans); font-size: .8rem; font-weight: 800;
    letter-spacing: .13em; text-transform: uppercase; color: #FBF4EF;
    cursor: pointer; padding: 1.05rem 1.2rem;
    border: none; border-radius: 4px;
    background: var(--k-deep);
    box-shadow: 0 10px 22px -12px rgba(70, 40, 28, .8);
    transition: background .18s, transform .14s, box-shadow .18s;
}
.cmn-submit:hover { background: #6E483A; transform: translateY(-1px); box-shadow: 0 16px 28px -12px rgba(70, 40, 28, .85); }
.cmn-submit:active { transform: none; }
.cmn-submit:focus-visible { outline: 3px solid var(--k-accent); outline-offset: 3px; }
.cmn-submit[disabled] { opacity: .72; cursor: progress; transform: none; }

.cmn-formerr {
    margin: .9rem 0 0; padding: .6rem .9rem; border-radius: 6px;
    background: #FBEAE4; border: 1px solid #E9C2B4; color: #8A4433;
    font-size: .78rem; font-weight: 600;
}

.cmn-assure {
    display: grid; grid-template-columns: auto 1fr; gap: .6rem; align-items: start;
    margin: 1.1rem 0 0;
    font-size: .74rem; line-height: 1.55; color: var(--k-muted);
}
.cmn-assure .ico { color: var(--k-accent); opacity: .75; }
.cmn-assure svg { width: 17px; height: 17px; display: block; margin-top: 1px; }


/* ==================== THE MOBILE DOCK ====================
   Below the two-column breakpoint the brief drops to the bottom of the page, so
   the running total would be out of reach for the entire form. This keeps it —
   and the way out — pinned. Hidden entirely where the panel can follow instead. */
.cmn-dock { display: none; }

@media (max-width: 940px) {
    .cmn-dock {
        display: block;
        position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
        background: rgba(250, 244, 240, .96);
        backdrop-filter: blur(10px);
        border-top: 1px solid var(--k-line);
        box-shadow: 0 -8px 24px -18px rgba(80, 48, 34, .7);
        padding: .6rem clamp(1.2rem, 3vw, 3rem);
        padding-bottom: calc(.6rem + env(safe-area-inset-bottom, 0px));
    }
    .cmn-dock-inner {
        display: flex; align-items: center; justify-content: space-between; gap: 1rem;
        max-width: 1420px; margin: 0 auto;
    }
    .cmn-dock-total { display: flex; flex-direction: column; line-height: 1.15; }
    .cmn-dock-total em {
        font-style: normal; font-size: .6rem; font-weight: 800;
        letter-spacing: .16em; text-transform: uppercase; color: var(--k-muted);
    }
    .cmn-dock-total b {
        font-family: var(--k-serif); font-weight: 400; font-size: 1.5rem;
        color: var(--k-deep); font-variant-numeric: tabular-nums;
    }
    .cmn-dock-btn {
        font-family: var(--k-sans); font-size: .74rem; font-weight: 800;
        letter-spacing: .12em; text-transform: uppercase; color: #FBF4EF;
        cursor: pointer; padding: .85rem 1.3rem; border: none; border-radius: 4px;
        background: var(--k-deep);
        box-shadow: 0 8px 18px -10px rgba(70, 40, 28, .8);
    }
    .cmn-dock-btn:active { transform: translateY(1px); }
    /* clear the dock so the last row and the footer are not sitting under it */
    .cmn-layout { padding-bottom: 6.5rem; }
}


/* ==================== CONFIRMATION ==================== */
.cmn-done { padding: clamp(2.5rem, 6vw, 5rem) 0 5rem; }
.cmn-inner { width: 100%; max-width: 780px; margin: 0 auto; padding: 0 24px; }
.cmn-done-card {
    text-align: center; padding: clamp(2rem, 5vw, 3.4rem) clamp(1.4rem, 4vw, 3rem) 3rem;
    background: var(--k-card); border: 1px solid var(--k-line);
    border-radius: 6px; box-shadow: 0 24px 50px -34px rgba(80, 48, 34, .6);
}
.cmn-done-mark {
    display: block; font-family: var(--k-serif); font-size: 2.2rem;
    color: var(--k-gold); margin-bottom: .8rem;
}
.cmn-brandline {
    display: flex; align-items: center; justify-content: center; gap: .7rem;
    margin: 0 0 .9rem;
    font-size: .68rem; font-weight: 800; letter-spacing: .2em; text-transform: uppercase;
    color: var(--k-accent);
}
.cmn-brandline .sep { width: 26px; height: 1px; background: currentColor; opacity: .45; }
.cmn-done-card h1 {
    font-family: var(--k-serif); font-weight: 400;
    font-size: clamp(1.8rem, 4.2vw, 2.6rem); color: var(--k-deep); margin: 0 0 1rem;
}
.cmn-lead { font-size: 1rem; color: var(--k-ink-2); max-width: 54ch; margin: 0 auto; line-height: 1.65; }
.cmn-done-note {
    margin: 1.3rem auto 0; max-width: 50ch;
    font-family: var(--k-serif); font-style: italic; font-size: .98rem; color: var(--k-ink-2);
}
.cmn-done-summary { margin-top: 2.2rem; text-align: left; }
.cmn-summary {
    margin: 0; padding: 1.2rem 1.4rem;
    background: var(--k-panel-2); border: 1px solid var(--k-line-soft); border-radius: 6px;
}
.cmn-summary > div {
    display: grid; grid-template-columns: 1fr auto; gap: 1rem; align-items: baseline;
    padding: .55rem 0; border-bottom: 1px solid #EBDDD4;
}
.cmn-summary > div:last-child { border-bottom: none; padding-bottom: 0; }
.cmn-summary > div:first-child { padding-top: 0; }
.cmn-summary dt {
    font-size: .68rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
    color: var(--k-muted);
}
.cmn-summary dd {
    margin: 0; text-align: right; font-size: .88rem; font-weight: 600; color: var(--k-ink);
}
.cmn-done-notes {
    margin-top: 1.1rem; padding: 1.1rem 1.3rem; text-align: left;
    background: var(--k-panel-2); border-radius: 6px; border: 1px solid var(--k-line-soft);
}
.cmn-done-notes b {
    display: block; font-size: .66rem; font-weight: 800;
    letter-spacing: .14em; text-transform: uppercase; color: var(--k-accent); margin-bottom: .45rem;
}
.cmn-done-notes p { margin: 0; white-space: pre-line; color: var(--k-ink-2); font-size: .9rem; }
.cmn-done-warn {
    margin-top: 1.3rem; padding: .9rem 1.1rem; text-align: left;
    background: #FDF4E7; border: 1px solid #EBD5B4; border-radius: 6px;
    font-size: .84rem; color: #7A5A2E;
}
.cmn-done-warn b { display: block; margin-bottom: .35rem; }
.cmn-done-warn ul { margin: 0 0 .5rem; padding-left: 1.1rem; }
.cmn-done-warn p { margin: 0; }
.cmn-done-actions { display: flex; flex-wrap: wrap; gap: .8rem; justify-content: center; margin-top: 2rem; }
.cmn-fineprint { margin: 1.2rem 0 0; font-size: .76rem; color: var(--k-muted); }


/* ==================== RESPONSIVE ==================== */
@media (max-width: 1180px) {
    .cmn-layout { grid-template-columns: minmax(0, 1fr) 330px; }
    .cmn-tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .cmn-sizes { --cmn-in: 13px !important; }
    .cmn-pages { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .cmn-formats { grid-template-columns: 1fr; }
    .cmn-details { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 940px) {
    /* The brief stops being a sidebar and becomes the last thing you read before
       submitting — which is the right order for it anyway once it cannot be
       pinned beside the form. */
    .cmn-layout { grid-template-columns: 1fr; }
    .cmn-brief-inner { position: static; max-height: none; }
    .cmn-head { flex-direction: column; gap: 1rem; }
    .cmn-head-note { max-width: none; }
    .cmn-how ol { grid-template-columns: repeat(2, 1fr); gap: 1.2rem .4rem; }
    .cmn-how li + li::before { display: none; }
}

@media (max-width: 700px) {
    .cmn-row { grid-template-columns: 1fr; gap: .9rem; padding: 1.4rem 0; }
    .cmn-row-label { grid-template-columns: auto 1fr; }
    .cmn-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .cmn-leathers { grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); }
    .cmn-metals, .cmn-cords { grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); }
    .cmn-charms { grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); }
    /* Restated rather than inherited: the desktop `.is-upgraded` rule outranks a
       bare `.cmn-charms` one, media query or not. */
    .cmn-charms.is-upgraded { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
    .cmn-pages { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .cmn-details { grid-template-columns: 1fr; }
    .cmn-how ol { grid-template-columns: 1fr; text-align: left; }
    .cmn-how li { display: grid; grid-template-columns: auto 1fr; gap: .1rem .8rem; text-align: left; padding: 0; }
    .cmn-how .n { grid-row: span 2; margin: 0; }
    /* The sizes keep their shared baseline — with two of them they still fit
       side by side on a phone — but the scale comes down to make room. */
    .cmn-sizes { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); --cmn-in: 10px !important; }
}

@media (prefers-reduced-motion: reduce) {
    .cmn *, .cmn *::before, .cmn *::after { transition: none !important; animation: none !important; }
}


/* ============================================================
   PHONE · THE GUIDED FLOW

   On a desk this page is nine numbered rows beside a pinned
   brief, and it works: the brief is always in view, so the
   length of the form costs nothing.

   On a phone the brief cannot be pinned, so it drops to the
   bottom — and the page measured 6,813px, a little over eight
   screens, with the summary and the submit button five screens
   below the first choice. Nothing was broken; there was simply
   no way to see what you had chosen without leaving where you
   were choosing it.

   So on a phone the same nine rows are dealt out as six steps,
   and the dock at the bottom becomes the whole instrument: it
   carries the progress, the running total, and both directions
   of travel, all inside thumb reach. The markup is untouched —
   every input stays in the DOM and the form posts exactly as it
   does now — and the flow is built by script, so a browser that
   never runs it still gets the full page, scrolling.
   ============================================================ */

/* Only ever set by the script, and only under the breakpoint. */
.cmn-layout.is-stepped .cmn-row { display: none; }
.cmn-layout.is-stepped .cmn-row.is-current { display: grid; }
.cmn-layout.is-stepped .cmn-brief { display: none; }
.cmn-layout.is-stepped .cmn-brief.is-current { display: block; }

/* The masthead and How It Works are ~820px of preamble — most of the first
   screen before a single choice. Worth reading once; not worth carrying
   through all six steps. */
.cmn.is-stepped:not(.at-first) .cmn-how,
.cmn.is-stepped:not(.at-first) .cmn-head-note,
.cmn.is-stepped:not(.at-first) .cmn-head-main p { display: none; }
.cmn.is-stepped:not(.at-first) .cmn-head { padding-bottom: .4rem; }
.cmn.is-stepped:not(.at-first) .cmn-head h1 { font-size: 1.45rem; margin: 0; }

/* A step arrives from the right, briefly. It reads as travel rather than as a
   page that swapped its contents while you were not looking. */
@keyframes cmn-step-in {
    from { opacity: 0; transform: translateX(9px); }
    to   { opacity: 1; transform: none; }
}
.cmn-layout.is-stepped .cmn-row.is-current,
.cmn-layout.is-stepped .cmn-brief.is-current { animation: cmn-step-in .26s ease both; }

@media (max-width: 940px) {
    /* ---------- the dock, promoted ---------- */
    .cmn-dock.is-stepped { padding-top: 0; }
    .cmn-dock.is-stepped .cmn-dock-inner {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr) auto;
        align-items: center; gap: .5rem .8rem;
    }

    /* Six segments across the top edge of the dock. Each is a real button —
       going back three steps to change a leather should not mean pressing
       Back three times — padded to a 34px target while the bar it draws stays
       3px, via a content-box background. */
    .cmn-dock-ticks {
        grid-column: 1 / -1;
        display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
        gap: 4px; list-style: none; margin: 0; padding: 0;
    }
    /* box-sizing is border-box site-wide, so `height` is the target and the
       padding is what shrinks the bar inside it — 36px to press, 3px drawn. */
    .cmn-dock-ticks button {
        display: block; width: 100%; height: 36px; padding: 16.5px 0;
        border: none; background: #E3D2C9; background-clip: content-box;
        border-radius: 2px; cursor: pointer;
        -webkit-tap-highlight-color: transparent;
        transition: background .2s ease;
    }
    .cmn-dock-ticks button[aria-current="step"] { background: var(--k-deep); background-clip: content-box; }
    .cmn-dock-ticks button.is-done { background: var(--k-accent); background-clip: content-box; }
    .cmn-dock-ticks button:focus-visible { outline: 2px solid var(--k-accent); outline-offset: 1px; }

    .cmn-dock-step {
        grid-column: 1 / -1; margin: -.25rem 0 .1rem;
        font-size: .62rem; font-weight: 800; letter-spacing: .14em;
        text-transform: uppercase; color: var(--k-muted);
    }
    .cmn-dock-step b { color: var(--k-deep); font-weight: 800; }

    .cmn-dock-back {
        display: grid; place-items: center;
        width: 46px; height: 46px; padding: 0;
        font-size: 1.2rem; line-height: 1; color: var(--k-ink-2);
        background: transparent; border: 1px solid var(--k-line);
        border-radius: 4px; cursor: pointer;
        -webkit-tap-highlight-color: transparent;
        transition: border-color .16s, color .16s;
    }
    .cmn-dock-back:disabled { opacity: .3; cursor: default; }
    .cmn-dock-back:not(:disabled):active { border-color: var(--k-accent); color: var(--k-accent); }

    .cmn-dock.is-stepped .cmn-dock-total { align-items: flex-start; }
    .cmn-dock.is-stepped .cmn-dock-btn { min-height: 46px; padding: .85rem 1.5rem; }

    /* The last row and the footer have to clear a dock whose height now depends
       on what is in it, so the script measures it and sets the variable. */
    .cmn-layout { padding-bottom: calc(var(--cmn-dock-h, 6.5rem) + 1.5rem); }
}


/* ============================================================
   PHONE · EVERYTHING ELSE
   ============================================================ */
@media (max-width: 940px) {
    /* iOS zooms the page when a field under 16px takes focus, and does not zoom
       back. These were .92rem — every text field on the page did it.
       site.css sets the same rule, but .cmn-field wins on order, so it has to
       be said again here. */
    .cmn-field input, .cmn-field textarea { font-size: 16px; }
}

@media (max-width: 700px) {
    /* ---------- targets ----------
       Measured before: Edit 30×25, prompt chips 107×29, the view buttons 65×22.
       All well under the 44px a finger can land on. */
    .cmn-edit {
        display: grid; place-items: center;
        min-width: 52px; min-height: 44px; margin: -.6rem -.4rem -.6rem 0;
        font-size: .74rem;
        -webkit-tap-highlight-color: transparent;
    }
    .cmn-prompt { min-height: 44px; padding: .5rem 1rem; font-size: .8rem; }
    .cmn-prompts { gap: .5rem; }

    /* ---------- the view buttons ----------
       These sit in the strip above the picture at every width, the same as the
       desktop. They spent a while as a round icon over the tile's top-left
       corner, which was the better trade while every tile was a drawn swatch:
       there is no hover on a phone, so the pills were permanently visible and a
       row of them read as clutter over a row of colours.

       Photographs reversed it. The badge landed on the picture and covered the
       one thing the button exists to show you — which is the whole argument for
       the strip in the first place. So: back above the tile, and made bigger
       rather than smaller, because the reason it moved was the 44px target.

       (It cannot go inside the label at all — the press would be forwarded and
       select the option instead of opening the picture.) */
    .cmn-viewbar {
        /* Taller than the desktop's 20px so the button fits, and applied to the
           empty bars too, so a tile with no photograph still lines its picture
           up with the photographed one beside it. */
        min-height: 36px;
        margin-bottom: 2px;
        align-items: center;
    }
    /* Qualified with .iv-open deliberately. The pill's own styling lives in
       image-viewer.css, which the view loads *after* commission.css — at equal
       specificity that stylesheet wins, so a bare .cmn-view here is overruled
       and the button keeps its label and padding. */
    .cmn-view.iv-open {
        min-height: 34px;
        padding: .4rem .8rem;
        gap: .34rem;
        font-size: .6rem;
        -webkit-tap-highlight-color: transparent;
    }
    .cmn-view.iv-open svg { width: 12px; height: 12px; }

    /* ---------- density ---------- */
    .cmn-row { padding: 1.2rem 0; }
    .cmn-head { padding-top: 1.4rem; }
    .cmn-drop.is-lg .cmn-drop-face { padding: 1.8rem 1.1rem; }
    .cmn-field-lg textarea { min-height: 132px; }

    /* Given a step of its own, the hides get to be the size of the decision.
       Two across at 390px draws each swatch about 170px wide — a piece of
       leather you can actually judge, rather than a 96px chip. */
    .cmn-leathers { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .7rem; }
    .cmn-leather-name { font-size: .74rem; margin-top: .5rem; }
    .cmn-leather-type { font-size: .64rem; }

    /* Hardware and elastic share the leather's step but not its generosity: a
       metal and a cord are judged at a glance, where a hide is not. Three across
       keeps the step from turning into a scroll of its own. */
    .cmn-metals, .cmn-cords { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .6rem; }
    .cmn-metal-name, .cmn-cord-name { font-size: .72rem; margin-top: .5rem; }
}

@media (max-width: 380px) {
    .cmn-charms, .cmn-charms.is-upgraded { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .cmn-pages { grid-template-columns: 1fr; }
    .cmn-metals, .cmn-cords { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
