/* ============================================================
   The Masterpiece Portfolio — all styles.
   Sections: base / room shell / world (tiles + panels) /
   chrome (topbar, chips, hint) / work card / cart drawer /
   about + contact modals / veil + intro / media queries
   ============================================================ */

/* ---------- base ---------- */
html,body{margin:0;height:100%;overflow:hidden;background:var(--t-void);color:#26231d;font-family:Archivo,system-ui,sans-serif}
a{color:#26231d}a:hover{color:#6f6a5e}
@keyframes tmpFade{from{opacity:0}to{opacity:1}}
@keyframes tmpSlide{from{transform:translateX(100%)}to{transform:translateX(0)}}
@keyframes tmpIntro{0%{opacity:1}68%{opacity:1}100%{opacity:0}}
@keyframes tmpRise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:translateY(0)}}
#stage{position:absolute;inset:0;perspective:950px;perspective-origin:50% 46%;touch-action:none;cursor:grab}
#stage,#ui{-webkit-user-select:none;user-select:none}
/* ---------- room presets: the light a room hangs in ---------- */
/* Content stores only an id ("evening"); every colour lives here. That way a
   preset can be retuned for every gallery at once without anyone editing a
   content file, and a manager can never mix a colour of their own.
   Bare :root IS the house look — its values are today's literals verbatim, so
   an untouched content.json renders byte-identically to the pre-preset site.
   A preset is swapped INSTANTLY under the opaque #veil during a room change:
   gradients cannot css-transition, and animating surfaces this large mid-walk
   would stutter. Never add a transition to any property below.
   CONTRAST DOCTRINE: every one of these palettes clears WCAG AA (4.5:1) for
   its small type against the surface that type actually sits on. The greys
   here are DARKER than the site's original secondary greys, which measured
   2.5-3.3:1 — a caption a gallery's own visitors could not read. Tokenising
   is what made that measurable: contrast is now a property of the palette,
   checked in one place. Do not lighten these without re-running the check.
   A dark room is not a dark wall.
   --contact is the shading where a wall meets the floor. It exists because
   the floor is rendered THROUGH the room's light, which keeps every pairing
   deliberate but does NOT keep the floor VISIBLE: three of the twenty-four
   pairings landed within 1.03:1 of their own wall, and a room whose floor
   has the same value as its wall has lost its corner. Real rooms are darker
   in that join, so the fix is the true one rather than a nudge to the
   palette. Calibrated so no room separates worse than the house light
   already does — which is why skylight's is transparent and today's room is
   untouched. Dark rooms take a light rim instead: black on near-black is
   not a shadow, it is nothing. Frames, glow, vignette,
   grain and type all move together or the room is not finished — a white mat
   glaring out of a dim room is the failure this vocabulary exists to prevent. */
:root,
body[data-atmos="skylight"]{
  /* SKYLIGHT — the house light, verbatim from the original file. */
  --wall-1:#f8f6f1; --wall-2:#f1eee6; --wall-3:#ddd7c8;
  --ceil-1:#f4f1ea; --ceil-2:#faf8f3;
  --end-1:#f6f4ee;  --end-2:#e8e3d6;
  --void:#efece4;
  --air:#efece4; --air-amt:0%;   /* 0% mix = the floor material renders raw = today's bytes */
  --ink:#26231d; --ink-hover:#6f6a5e; --title:#33302a;
  --stmt-1:#46423a; --stmt-2:#6b665c; --muted:#6a665a; --label:#6a6558; --faint:#646157;
  --mat:#ffffff;
  --frame-shadow:0 20px 34px -16px rgba(52,44,26,.5);
  --frame-shadow-hover:0 30px 46px -18px rgba(52,44,26,.62);
  --pframe-shadow:0 18px 30px -14px rgba(52,44,26,.5);
  --glow-rgb:255,254,248; --glow-tile:.95; --glow-panel:.9;
  --vig-in:rgba(38,35,29,0); --vig-out:rgba(38,35,29,.14);
  --grain-opacity:.05; --grain-blend:multiply;
  --art-bg:#ece8dd; --hatch-1:#eeeade; --hatch-2:#f5f2e9;
  --contact:transparent;
  --paper-1:#46423a;
  --paper-2:#6b665c;
  --paper-label:#6e695b;
  --chrome-rgb:253,252,248; --chrome-border:#ddd7c8; --chrome-ink:#26231d;
  --chrome-muted:#57534a; --crumb-sep:#c3bda9;
}
body[data-atmos="northlight"]{
  /* NORTH LIGHT — cool, even, shadowless painter's daylight. Blue-leaning,
     never green: green-grey is the one tint that hurts skin and warm oils. */
  --wall-1:#f4f6f6; --wall-2:#ebeeee; --wall-3:#d5dadb;
  --ceil-1:#f1f5f5; --ceil-2:#fafcfc;
  --end-1:#f2f4f4;  --end-2:#e0e5e5;
  --void:#e8ebea;
  --air:#dde3e6; --air-amt:10%;
  --ink:#222524; --ink-hover:#5f6567; --title:#2d302f;
  --stmt-1:#424744; --stmt-2:#656b69; --muted:#616766; --label:#636766; --faint:#5f6362;
  --mat:#ffffff;
  --frame-shadow:0 22px 40px -18px rgba(40,46,48,.42);
  --frame-shadow-hover:0 30px 50px -20px rgba(40,46,48,.5);
  --pframe-shadow:0 18px 32px -16px rgba(40,46,48,.42);
  --glow-rgb:250,252,253; --glow-tile:.7; --glow-panel:.65;
  --vig-in:rgba(30,34,36,0); --vig-out:rgba(30,34,36,.12);
  --grain-opacity:.05; --grain-blend:multiply;
  --art-bg:#e8eaea; --hatch-1:#ebedee; --hatch-2:#f3f5f5;
  --contact:rgba(20,17,13,.29);
  --paper-1:#424744;
  --paper-2:#656b69;
  --paper-label:#666a69;
  --chrome-rgb:251,252,252; --chrome-border:#d4d9da; --chrome-ink:#222524;
  --chrome-muted:#545859; --crumb-sep:#b9bfc0;
}
body[data-atmos="kunsthalle"]{
  /* KUNSTHALLE — mid-grey concrete under a diffuse rooflight slot. White mats
     on grey are the signature, so --mat stays pure white on purpose. */
  --wall-1:#d8d7d2; --wall-2:#cfceca; --wall-3:#bdbcb6;
  --ceil-1:#dcdbd7; --ceil-2:#e5e4e0;
  --end-1:#d5d4cf;  --end-2:#c4c3bd;
  --void:#c9c8c3;
  --air:#4b4c4e; --air-amt:10%;
  --ink:#1f201c; --ink-hover:#55564f; --title:#2a2b27;
  --stmt-1:#393a34; --stmt-2:#55564f; --muted:#51524c; --label:#51524d; --faint:#4f504b;
  --mat:#ffffff;
  --frame-shadow:0 18px 32px -15px rgba(24,26,25,.38);
  --frame-shadow-hover:0 28px 44px -17px rgba(24,26,25,.48);
  --pframe-shadow:0 16px 28px -13px rgba(24,26,25,.38);
  --glow-rgb:250,250,247; --glow-tile:.5; --glow-panel:.45;
  --vig-in:rgba(20,21,22,0); --vig-out:rgba(20,21,22,.2);
  --grain-opacity:.07; --grain-blend:multiply;   /* concrete has tooth */
  --art-bg:#c6c5c0; --hatch-1:#c9c8c2; --hatch-2:#d1d0ca;
  --contact:rgba(20,17,13,.24);
  --paper-1:#393a34;
  --paper-2:#55564f;
  --paper-label:#52534e;
  --chrome-rgb:246,246,244; --chrome-border:#b7b6b0; --chrome-ink:#1f201c;
  --chrome-muted:#45463f; --crumb-sep:#96958f;
}
body[data-atmos="lamplight"]{
  /* LAMPLIGHT — tungsten picture lights on honeyed cream: the townhouse hang.
     The ceiling is DARKER than the walls (light aims down) — the cue that this
     room is lamp-lit rather than merely repainted. */
  --wall-1:#f0e5d0; --wall-2:#e4d6bb; --wall-3:#c8b596;
  --ceil-1:#d6c9ae; --ceil-2:#dfd3ba;
  --end-1:#ecdfc6;  --end-2:#d3c1a0;
  --void:#d8cbaf;
  --air:#d8ac6a; --air-amt:12%;
  --ink:#2b2418; --ink-hover:#5c5138; --title:#382f1f;
  --stmt-1:#4c4130; --stmt-2:#685b44; --muted:#5e523a; --label:#5e523b; --faint:#594e33;
  --mat:#fdf8ee;   /* white under tungsten reads warm-white */
  --frame-shadow:0 22px 36px -16px rgba(56,40,16,.55);
  --frame-shadow-hover:0 32px 48px -18px rgba(56,40,16,.66);
  --pframe-shadow:0 18px 30px -14px rgba(56,40,16,.55);
  --glow-rgb:255,236,196; --glow-tile:.95; --glow-panel:.9;   /* the glow IS the picture light */
  --vig-in:rgba(42,31,15,0); --vig-out:rgba(42,31,15,.24);
  --grain-opacity:.06; --grain-blend:multiply;
  --art-bg:#e6dcc4; --hatch-1:#e8ddc2; --hatch-2:#f0e7d0;
  --contact:rgba(20,17,13,.17);
  --paper-1:#4c4130;
  --paper-2:#6e6149;
  --paper-label:#60543c;
  --chrome-rgb:252,246,232; --chrome-border:#d3c3a2; --chrome-ink:#2b2418;
  --chrome-muted:#5c5138; --crumb-sep:#bfae85;
}
body[data-atmos="evening"]{
  /* EVENING — the dark hang: umber walls sunk to dusk, ceiling darkest, each
     work pooled in its own warm light. */
  --wall-1:#564e41; --wall-2:#4a4337; --wall-3:#3a342a;
  --ceil-1:#2c2721; --ceil-2:#332d26;   /* value order inverted: the room reads lamp-lit */
  --end-1:#524a3d;  --end-2:#3e3830;
  --void:#2b2620;
  --air:#2b2620; --air-amt:42%;
  --ink:#f0e9dc; --ink-hover:#cfc5b2; --title:#ece4d3;
  --stmt-1:#e6ddc9; --stmt-2:#c7bca6; --muted:#cac1af; --label:#c8beac; --faint:#c6bcac;
  --mat:#f7f2e7;   /* lamplit paper, not glare */
  --frame-shadow:0 0 0 1px rgba(255,243,214,.07), 0 24px 40px -16px rgba(10,8,5,.55);
  --frame-shadow-hover:0 0 0 1px rgba(255,243,214,.11), 0 32px 52px -18px rgba(10,8,5,.62);
  --pframe-shadow:0 0 0 1px rgba(255,243,214,.07), 0 20px 34px -14px rgba(10,8,5,.55);
  --glow-rgb:255,241,209; --glow-tile:.16; --glow-panel:.14;
  --vig-in:rgba(10,8,5,0); --vig-out:rgba(10,8,5,.5);
  --grain-opacity:.06; --grain-blend:screen;   /* multiply dies on dark walls */
  --art-bg:#3c362c; --hatch-1:#423b31; --hatch-2:#4a4338;
  --contact:rgba(255,250,238,.05);
  --paper-1:#4b4946;
  --paper-2:#6d6a66;
  --paper-label:#6d6a66;
  --chrome-rgb:30,25,19; --chrome-border:rgba(255,243,214,.18); --chrome-ink:#f0e9dc;
  --chrome-muted:#d9cfbb; --crumb-sep:#7a705d;
}
body[data-atmos="nocturne"]{
  /* NOCTURNE — a neutral black box; the art is the only light in the room.
     Warm-neutral charcoal (R>=G>=B), never blue. */
  --wall-1:#262523; --wall-2:#201f1d; --wall-3:#171614;
  --ceil-1:#131211; --ceil-2:#181716;
  --end-1:#232220;  --end-2:#191816;
  --void:#121110;
  --air:#211f1c; --air-amt:88%;   /* every floor sinks to one step above the wall */
  --ink:#e9e6df; --ink-hover:#b5b0a2; --title:#e4e0d7;
  --stmt-1:#ddd8cd; --stmt-2:#b3aea3; --muted:#a19c92; --label:#908b81; --faint:#908c81;
  --mat:#eae6dc;   /* bone — pure white burns in a black box */
  --frame-shadow:0 0 0 1px rgba(240,240,235,.08), 0 22px 40px -18px rgba(0,0,0,.8);
  --frame-shadow-hover:0 0 0 1px rgba(240,240,235,.14), 0 30px 50px -20px rgba(0,0,0,.85);
  --pframe-shadow:0 0 0 1px rgba(240,240,235,.08), 0 18px 32px -14px rgba(0,0,0,.8);
  --glow-rgb:255,250,238; --glow-tile:.12; --glow-panel:.1;
  --vig-in:rgba(0,0,0,0); --vig-out:rgba(0,0,0,.55);
  --grain-opacity:.08; --grain-blend:screen;   /* star-dust, an echo of Earthlight */
  --art-bg:#1c1b19; --hatch-1:#201f1c; --hatch-2:#262523;
  --contact:rgba(255,250,238,.17);
  --paper-1:#43423f;
  --paper-2:#65635f;
  --paper-label:#65635f;
  --chrome-rgb:19,18,17; --chrome-border:rgba(240,240,235,.16); --chrome-ink:#e7e3d8;
  --chrome-muted:#c9c4b9; --crumb-sep:#5c5850;
}
/* The floor is a MATERIAL; the room's light falls on it (see --air/--air-amt
   where #floor3d is drawn). That is why any floor may be paired with any
   atmosphere: the pairing is computed, not curated. */
:root,
body[data-floor="chalk"]{ --floor-1:#cfc9b9; --floor-2:#e6e1d3; --floor-3:#eae5d8; }
body[data-floor="oak"]{      /* white-oiled boards, desaturated so no light curdles them */
  --floor-1:#cbb999; --floor-2:#ddcdae; --floor-3:#e4d7bc; }
body[data-floor="walnut"]{   /* dark oiled boards — grounds a bright room, deepens a dim one */
  --floor-1:#463b2f; --floor-2:#574a3b; --floor-3:#5f5242; }
body[data-floor="concrete"]{ /* power-floated slab — the floor that disappears */
  --floor-1:#a9a7a1; --floor-2:#bbb9b3; --floor-3:#c2c0ba; }

/* ---------- surfaces a room declines to paint ----------
   A room in the dark reads better without a floor insisting it is a floor.
   These rules take the SURFACE away and nothing else: the element stays, its
   geometry stays, and — this is the point — the far wall's signage stays. The
   artist's name and medium are children of #backwall, so hiding that element
   would quietly delete an artist's name from their own room; making it stop
   painting leaves the name hanging in open dark, which is the better look and
   the safer behaviour at once.
   Opacity is deliberately untouched: the culling loop owns that on every one
   of these elements, writing it inline every frame, and two owners of one
   property is a fight nobody wins. */
body[data-hide~="floor"]   #floor3d { background:none }
body[data-hide~="ceiling"] #ceil3d  { background:none }
body[data-hide~="back"]    #backwall{ background:none }
body[data-hide~="front"]   #frontwall{ background:none }

/* ---------- the tint dial: the hue of the light ----------
   A gel over a designed rig. The six atmospheres carry more than wall colour
   — frames, glow, vignette, grain and type were tuned together — so the dial
   does NOT let anyone mix their own room. It rotates the HUE of the light and
   leaves everything else standing.

   THE GUARANTEE, and the reason it is built this way: every contrast promise
   in this gallery rests on lightness. So the tint is applied in oklch, holding
   l EXACTLY and adding a bounded amount of chroma at the chosen hue. Lightness
   cannot move, and the chroma ceiling was not guessed — the inks were solved
   against the worst hue on the circle, then 8,640 contrast checks (6 rooms x
   120 hues x every text pair) confirmed the tightest point anywhere is 4.55:1
   against a floor of 4.5. Raising --tint-cap invalidates that; re-run the
   sweep if you ever do.

   --t-* mirror the plain tokens and default to them, so a room with no tint
   resolves to exactly the colours it always had. Only the room's SURFACES are
   tinted: the mat is paper and stays paper, and type is never tinted at all —
   which is what keeps the arithmetic above true. */
:root{
  --tint-cap:0.045;
  --tint-s:0;                       /* 0..1, set from the dial's strength */
  --t-wall-1:var(--wall-1); --t-wall-2:var(--wall-2); --t-wall-3:var(--wall-3);
  --t-ceil-1:var(--ceil-1); --t-ceil-2:var(--ceil-2);
  --t-end-1:var(--end-1);   --t-end-2:var(--end-2);
  --t-floor-1:var(--floor-1); --t-floor-2:var(--floor-2); --t-floor-3:var(--floor-3);
  --t-void:var(--void);
}
@supports (color: oklch(from white l c h)){
  body[data-tint]{
    /* DERIVED HERE, NOT ON :root. A custom property computes on the element it
       is declared on and inherits as a finished value, so --tint-c written at
       the root would bake in the root's --tint-s (zero) and never notice the
       strength the engine writes onto the body. It cost a wall that refused to
       change colour while every attribute said it should. */
    --tint-c:calc(var(--tint-s) * var(--tint-cap));
    --t-wall-1:oklch(from var(--wall-1) l calc(c + var(--tint-c)) var(--tint-h));
    --t-wall-2:oklch(from var(--wall-2) l calc(c + var(--tint-c)) var(--tint-h));
    --t-wall-3:oklch(from var(--wall-3) l calc(c + var(--tint-c)) var(--tint-h));
    --t-ceil-1:oklch(from var(--ceil-1) l calc(c + var(--tint-c)) var(--tint-h));
    --t-ceil-2:oklch(from var(--ceil-2) l calc(c + var(--tint-c)) var(--tint-h));
    --t-end-1:oklch(from var(--end-1) l calc(c + var(--tint-c)) var(--tint-h));
    --t-end-2:oklch(from var(--end-2) l calc(c + var(--tint-c)) var(--tint-h));
    --t-floor-1:oklch(from var(--floor-1) l calc(c + var(--tint-c)) var(--tint-h));
    --t-floor-2:oklch(from var(--floor-2) l calc(c + var(--tint-c)) var(--tint-h));
    --t-floor-3:oklch(from var(--floor-3) l calc(c + var(--tint-c)) var(--tint-h));
    --t-void:oklch(from var(--void) l calc(c + var(--tint-c)) var(--tint-h));
  }
}

/* ---------- room shell ---------- */
#shell,#world{position:absolute;inset:0;transform-style:preserve-3d;pointer-events:none}
.t3d{transition:transform 1.05s cubic-bezier(.3,.82,.24,1),opacity .3s ease}
/* A piece being zoomed or panned is answering a hand in real time, so it
   gives up the long glide for as long as that lasts — the glide belongs to
   approaching a work and stepping back from it, and is handed straight back
   when the zoom returns to fit. The culling fade is untouched. */
.t3d.zlive{transition:opacity .3s ease}
.tile.zlive{cursor:grab}
/* the hover lift is a cue for art on a wall you are walking past; on the piece
   you are standing at it would be multiplied by the zoom and jump the artwork
   every time the pointer crossed it */
.tile.zfoc:hover .frame{transform:none}
.cullable{transition:opacity .3s ease}
.mono{font-family:ui-monospace,Menlo,monospace}
.btn{background:#26231d;color:#fdfcf8;border:none;padding:13px 0;font-family:Archivo,sans-serif;font-size:11px;letter-spacing:.16em;text-transform:uppercase;cursor:pointer;width:100%}
.btn.ghost{background:rgba(253,252,248,0);color:#26231d;border:1px solid #26231d}

/* ---------- room shell (pinned to viewer; rotates only) ---------- */
#wallL,#wallR{position:absolute;left:50%;top:50%;width:800px;height:155px;margin:-77.5px 0 0 -400px;background:linear-gradient(180deg,transparent 58%,var(--contact,transparent) 100%),linear-gradient(180deg,var(--t-wall-1) 0%,var(--t-wall-2) 62%,var(--t-wall-3) 100%);-webkit-mask-image:linear-gradient(90deg,transparent,#000 18%,#000 82%,transparent);mask-image:linear-gradient(90deg,transparent,#000 18%,#000 82%,transparent)}
#wallL{transform:translate3d(-360px,0,0) rotateY(90deg) scale(4)}
#wallR{transform:translate3d(360px,0,0) rotateY(-90deg) scale(4)}
#floor3d,#ceil3d{position:absolute;left:50%;top:50%;width:180px;height:800px;margin:-400px 0 0 -90px;-webkit-mask-image:linear-gradient(180deg,transparent,#000 18%,#000 82%,transparent);mask-image:linear-gradient(180deg,transparent,#000 18%,#000 82%,transparent)}
#floor3d{transform:translate3d(0,310px,0) rotateX(90deg) scale(4);background:linear-gradient(180deg,var(--t-floor-1) 0%,var(--t-floor-2) 55%,var(--t-floor-3) 100%)}
/* The room's light falling on the floor. This is an ENHANCEMENT, deliberately
   not the declaration above: an unsupported color-mix() would invalidate the
   whole background and leave the floor missing — a room broken by a feature
   nobody switched on. Where it is supported, --air-amt:0% on the house light
   mixes to the raw material, so the default is identical either way. */
@supports (background:color-mix(in srgb,#000,#fff 50%)){
  #floor3d{background:linear-gradient(180deg,color-mix(in srgb,var(--t-floor-1),var(--air) var(--air-amt)) 0%,color-mix(in srgb,var(--t-floor-2),var(--air) var(--air-amt)) 55%,color-mix(in srgb,var(--t-floor-3),var(--air) var(--air-amt)) 100%)}
}
#ceil3d{transform:translate3d(0,-310px,0) rotateX(90deg) scale(4);background:linear-gradient(180deg,var(--t-ceil-1) 0%,var(--t-ceil-2) 100%)}
.vignette{position:absolute;inset:0;pointer-events:none;background:radial-gradient(ellipse 90% 80% at 50% 44%,var(--vig-in) 58%,var(--vig-out) 100%)}
.grain{position:absolute;inset:0;pointer-events:none;opacity:var(--grain-opacity);mix-blend-mode:var(--grain-blend);background:url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22240%22 height=%22240%22%3E%3Cfilter id=%22n%22%3E%3CfeTurbulence type=%22fractalNoise%22 baseFrequency=%220.9%22 numOctaves=%222%22/%3E%3CfeColorMatrix type=%22saturate%22 values=%220%22/%3E%3C/filter%3E%3Crect width=%22240%22 height=%22240%22 filter=%22url(%23n)%22 opacity=%220.55%22/%3E%3C/svg%3E')}

/* ---------- world: end walls ---------- */
.endwall{position:absolute;left:50%;top:50%;width:1600px;height:1200px;margin:-600px 0 0 -800px;background:linear-gradient(180deg,var(--t-end-1),var(--t-end-2))}
#backwall{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px}
.backTitle{font-family:Newsreader,serif;font-style:italic;font-size:40px;color:var(--title)}
.backSub{font-size:9px;letter-spacing:.3em;color:var(--label);text-transform:uppercase}

/* ---------- world: art tiles ---------- */
.tile{position:absolute;left:50%;top:50%;width:340px;height:430px;margin:-215px 0 0 -170px;cursor:pointer;backface-visibility:hidden;display:flex;flex-direction:column;justify-content:center;pointer-events:auto}
.tile .glow{position:absolute;inset:-100px;background:radial-gradient(circle at 50% 38%,rgba(var(--glow-rgb),var(--glow-tile)),rgba(var(--glow-rgb),0) 60%)}
.tile .frame{position:relative;background:var(--mat);padding:12px;box-shadow:var(--frame-shadow);transition:transform .35s ease,box-shadow .35s ease}
.tile:hover .frame{transform:translateY(-6px);box-shadow:var(--frame-shadow-hover)}
.tile .cap{position:relative;margin-top:16px;text-align:center}
.tile .cap b{font-size:13px;font-weight:600;letter-spacing:.02em;display:block;color:var(--ink)}
.tile .cap span{margin-top:3px;font-size:9.5px;letter-spacing:.22em;text-transform:uppercase;color:var(--muted);display:block}
.art{width:100%;background-color:var(--art-bg);background-size:cover;background-position:center;transition:aspect-ratio .35s ease}
.artless{width:100%;aspect-ratio:1/1;display:flex;align-items:center;justify-content:center;background:repeating-linear-gradient(45deg,var(--hatch-1) 0 12px,var(--hatch-2) 12px 24px)}
.artless .mono{font-size:10px;color:var(--faint);text-align:center;line-height:1.7}

/* ---------- world: poem print (typeset panel — the type IS the artwork) ----------
   Drawn at double size inside .poemInner and scaled to half, so the letterforms
   rasterise cleanly when the zoom transform enlarges the tile. Star positions
   are fixed by hand — the sky must not shuffle between renders. No animations
   here: the tile's transform transition owns movement. */
.poemArt{position:relative;width:100%;aspect-ratio:3/4;overflow:hidden;background:#081021}
.poemInner{position:absolute;top:0;left:0;width:200%;height:200%;transform:scale(.5);transform-origin:0 0;background:linear-gradient(180deg,#0b1026 0%,#0a1124 46%,#050b18 100%)}
.poemStars{position:absolute;inset:0;background-image:
  radial-gradient(3px 3px at 8% 7%,rgba(226,239,255,.75) 0 45%,transparent 100%),
  radial-gradient(2.4px 2.4px at 22% 16%,rgba(226,239,255,.5) 0 45%,transparent 100%),
  radial-gradient(2.8px 2.8px at 36% 6%,rgba(226,239,255,.65) 0 45%,transparent 100%),
  radial-gradient(2.2px 2.2px at 54% 11%,rgba(226,239,255,.45) 0 45%,transparent 100%),
  radial-gradient(3.4px 3.4px at 67% 20%,rgba(233,244,255,.8) 0 45%,transparent 100%),
  radial-gradient(2.4px 2.4px at 81% 8%,rgba(226,239,255,.55) 0 45%,transparent 100%),
  radial-gradient(2.8px 2.8px at 90% 26%,rgba(226,239,255,.6) 0 45%,transparent 100%),
  radial-gradient(2.2px 2.2px at 14% 38%,rgba(226,239,255,.4) 0 45%,transparent 100%),
  radial-gradient(2.6px 2.6px at 78% 44%,rgba(226,239,255,.5) 0 45%,transparent 100%),
  radial-gradient(2px 2px at 30% 55%,rgba(226,239,255,.35) 0 45%,transparent 100%),
  radial-gradient(2.2px 2.2px at 88% 60%,rgba(226,239,255,.4) 0 45%,transparent 100%),
  radial-gradient(2.6px 2.6px at 10% 63%,rgba(226,239,255,.45) 0 45%,transparent 100%)}
/* the sunlit limb — a faint arc of earthglow under the line */
.poemEarthArc{position:absolute;left:-12%;right:-12%;top:72.75%;bottom:-45%;border-radius:50% 50% 0 0/100% 100% 0 0;background:radial-gradient(120% 100% at 50% 0%,rgba(79,168,216,.18),rgba(46,84,128,.10) 30%,rgba(5,11,24,0) 62%)}
/* the thin blue line, crested, with a soft glow above and below —
   the glow carries the faintest green-teal breath (aurora) */
.poemEarthline{position:absolute;left:7%;right:7%;top:71.5%;height:4px;border-radius:2px;background:linear-gradient(90deg,rgba(79,168,216,0),rgba(79,168,216,.85) 24%,#d9f2ff 50%,rgba(79,168,216,.85) 76%,rgba(79,168,216,0))}
.poemEarthline::before{content:'';position:absolute;left:-4%;right:-4%;top:-30px;bottom:-30px;background:radial-gradient(ellipse 52% 46% at 50% 50%,rgba(79,168,216,.28),rgba(110,214,188,.09) 58%,rgba(110,214,188,0) 80%)}
.poemEarthline::after{content:'';position:absolute;left:33%;right:33%;top:-1px;bottom:-1px;border-radius:3px;background:radial-gradient(ellipse 50% 100% at 50% 50%,rgba(217,242,255,.55),transparent 78%)}
.poemType{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;text-align:center;padding:8% 9% 7.5%;box-sizing:border-box}
.poemHead{display:flex;flex-direction:column;align-items:center}
.poemLabel{font-family:Archivo,sans-serif;font-size:13px;font-weight:500;letter-spacing:.5em;text-indent:.5em;text-transform:uppercase;color:rgba(148,183,215,.8)}
.poemTitle{margin-top:14px;font-family:Archivo,sans-serif;font-variant:small-caps;font-weight:500;font-size:30px;letter-spacing:.38em;text-indent:.38em;color:#dfeaf6}
/* title-mode: no lines yet — the title is the subject, sitting lower and
   larger, with the line and stars carrying the composition */
.poemArt.titleMode .poemHead{flex:1;justify-content:center;padding-bottom:13%}
.poemArt.titleMode .poemTitle{margin-top:22px;font-size:52px;letter-spacing:.3em;text-indent:.3em}
.poemLines{flex:1;display:flex;flex-direction:column;justify-content:center;padding:4% 0 12%}
.poemLine{font-family:Newsreader,serif;font-style:italic;font-size:26px;line-height:1.85;color:#cfe0ef;text-wrap:balance}
.poemLines.dense .poemLine{font-size:21px;line-height:1.7}
.poemLines.denser .poemLine{font-size:17px;line-height:1.6}
.poemLines.densest .poemLine{font-size:14px;line-height:1.5}
.poemLine.gap{height:.85em}
.poemBase{margin-top:auto;display:flex;flex-direction:column;align-items:center;gap:12px}
.poemRule{display:block;width:76px;height:2px;background:linear-gradient(90deg,transparent,rgba(198,220,240,.5),transparent)}
.poemBy{font-family:Archivo,sans-serif;font-size:14px;letter-spacing:.3em;text-indent:.3em;text-transform:uppercase;color:rgba(176,197,219,.75)}

/* ---------- world: wing identity panels (portrait + statement) ---------- */
.portraitPanel{position:absolute;left:50%;top:50%;width:240px;height:340px;margin:-170px 0 0 -120px;backface-visibility:hidden;pointer-events:auto;cursor:pointer}
.portraitPanel .pglow{position:absolute;inset:-80px;background:radial-gradient(circle at 50% 38%,rgba(var(--glow-rgb),var(--glow-panel)),rgba(var(--glow-rgb),0) 62%)}
.portraitPanel .pframe{position:relative;background:var(--mat);padding:10px;box-shadow:var(--pframe-shadow)}
.portraitPanel .pframe .artless{aspect-ratio:4/5}
.portraitPanel .pcap{position:relative;margin-top:12px;text-align:center;font-size:9px;letter-spacing:.24em;color:var(--muted)}
.stmtPanel{position:absolute;left:50%;top:50%;width:640px;height:460px;margin:-230px 0 0 -320px;backface-visibility:hidden;display:flex;flex-direction:column;justify-content:center;padding:0 30px;box-sizing:border-box;pointer-events:auto;cursor:pointer}
.stmtLabel{font-size:9.5px;letter-spacing:.3em;color:var(--label)}
.stmtBody{margin-top:18px}
.stmtBody.cols{column-count:2;column-gap:30px}
.stmtPrimary{margin:0;font-family:Newsreader,serif;color:var(--stmt-1);text-wrap:pretty;white-space:pre-line;font-size:17px;line-height:1.7}
.stmtPrimary.small{font-size:13px;line-height:1.65}
.stmtSecondary{margin:14px 0 0;font-family:Newsreader,serif;color:var(--stmt-2);text-wrap:pretty;white-space:pre-line;font-size:13.5px;line-height:1.65}
.stmtSecondary.small{font-size:11.5px;line-height:1.6}
.stmtEmpty{margin:18px 0 0;font-size:11px;line-height:1.8;color:var(--faint)}

/* ---------- the words wall: the reading pose ----------
   An artist's statement is the one thing in this gallery made of language,
   and until now it was the least readable thing in it: fitted whole to the
   wall, a long statement painted at ~7px in two columns on a phone, with the
   zoom deliberately excluded (zWork required pfocus==null). It could be
   stepped up to and not read.

   Reading is therefore a POSE, not a scale. The panel becomes a matted sheet
   clipped to the wall's own band, and the text scrolls INSIDE it. Two things
   follow by construction, which is why it is built this way:
     - the sheet's silhouette never changes, so text can never ride up over
       the chrome, off the wall, or onto the floor at any zoom;
     - the type is sized to a floor of 16 painted px BEFORE any gesture, so
       the statement is readable to someone who never touches it.
   At rest the wrappers are display:contents — they do not exist, and the
   untouched wall paints exactly as it always has. */
.stmtSheet,.stmtScroll{display:contents}
.stmtPanel.reading{display:block;padding:0;cursor:default}
.stmtPanel.reading .stmtSheet{display:block;position:relative;width:100%;height:100%;
  overflow:hidden;background:var(--mat);box-shadow:var(--pframe-shadow)}
.stmtPanel.reading .stmtScroll{display:block;box-sizing:border-box;padding:26px 30px 30px;
  transform-origin:0 0;will-change:transform}
/* reading is linear: a column break is a place to lose your line */
.stmtPanel.reading .stmtBody.cols{column-count:1}
/* At reading size the shrunk-for-the-wall sizes are wrong, and enlarging is a
   REFLOW, not a magnification: --rk grows the type and the column re-wraps to
   the same sheet width, so reading never costs a sideways scroll. Magnifying
   optically would push line-ends off the sheet and force horizontal panning to
   read a single line — exactly what WCAG 1.4.10 exists to forbid. */
.stmtPanel.reading .stmtPrimary,.stmtPanel.reading .stmtPrimary.small{
  font-size:calc(17px * var(--rk,1));line-height:1.7}
.stmtPanel.reading .stmtSecondary,.stmtPanel.reading .stmtSecondary.small{
  font-size:calc(13.5px * var(--rk,1));line-height:1.65}
.stmtPanel.reading .stmtLabel,.stmtPanel.reading .stmtOpen{font-size:calc(9.5px * var(--rk,1))}
/* THE SHEET IS PAPER, AND PAPER TAKES DARK INK — in every room, however dark.
   On the wall the statement is set in the room's own light, which in a dark
   hang means pale type on a dark surface. Lay that same type on a matted sheet
   and it is pale on pale: measured at 1.14:1 in Nocturne, which is invisible,
   and it shipped that way. The reading pose therefore has its own inks, tied
   to the paper rather than to the wall. Nothing here applies at rest. */
.stmtPanel.reading .stmtPrimary,.stmtPanel.reading .stmtPrimary.small{color:var(--paper-1)}
.stmtPanel.reading .stmtSecondary,.stmtPanel.reading .stmtSecondary.small{color:var(--paper-2)}
.stmtPanel.reading .stmtLabel,.stmtPanel.reading .stmtOpen{color:var(--paper-label)}
.stmtPanel.reading .stmtEmpty{color:var(--paper-2)}
.stmtPanel.reading .stmtEmpty{font-size:calc(11px * var(--rk,1))}
/* The label is a real button: the wall says "there are words here" to a
   pointer, and now says it to a keyboard too. Pixel-identical at rest. */
.stmtOpen{font:inherit;letter-spacing:inherit;color:inherit;background:none;border:0;
  padding:0;margin:0;text-align:left;cursor:pointer;display:block}
.stmtOpen:hover{text-decoration:underline;text-underline-offset:3px}
/* Reading without a gesture: the whole statement as a plain page. This is the
   path for anyone who cannot pinch — and the one that works at any size. */
.readtext{position:absolute;right:46px;bottom:36px;z-index:20;cursor:pointer;font:inherit;
  font-size:11.5px;letter-spacing:.08em;color:var(--chrome-ink);
  background:rgba(var(--chrome-rgb),.8);border:1px solid var(--chrome-border);padding:9px 16px}
.readtext:hover{background:rgba(var(--chrome-rgb),.95)}
/* a keyboard must be able to see where it is */
.stmtOpen:focus-visible,.readtext:focus-visible,#portrait3d:focus-visible,
.tile:focus-visible,.turnbtns button:focus-visible,.chip:focus-visible,
.crumb:focus-visible,.wordmark:focus-visible,.nav a:focus-visible{
  outline:2px solid var(--ink);outline-offset:3px}

/* ---------- chrome: topbar, nav, chips, turn buttons, hint ---------- */
.topbar{position:absolute;top:0;left:0;right:0;display:flex;justify-content:space-between;align-items:center;gap:14px;padding:22px 46px;z-index:20}
.wordmark{cursor:pointer;font-size:11px;letter-spacing:.34em;font-weight:600;text-decoration:none;white-space:nowrap;text-transform:uppercase}
.nav{display:flex;align-items:center;gap:22px;font-size:11.5px;letter-spacing:.08em}
.nav a{cursor:pointer;text-decoration:none;white-space:nowrap}
/* the topbar is chrome, not commerce paper: it follows the room's light */
.wordmark,.nav a,.crumbs{color:var(--ink)}
.wordmark:hover,.nav a:hover{color:var(--ink-hover)}
.nav a.cartlink{border:1px solid var(--chrome-ink);padding:8px 16px;background:rgba(var(--chrome-rgb),.7);color:var(--chrome-ink)}
.chip{position:absolute;left:46px;z-index:20;cursor:pointer;font-size:12px;color:var(--chrome-muted);text-decoration:none;background:rgba(var(--chrome-rgb),.8);padding:8px 14px;border:1px solid var(--chrome-border)}
/* The trail is LOCATION first and a way out second, so it is set as type in
   the topbar's own voice rather than boxed as a control — which is also what
   keeps the one boxed chip below it from ever reading as another rung. */
.crumbs{position:absolute;left:46px;top:72px;z-index:20;display:flex;align-items:center;gap:7px;max-width:calc(100% - 92px);font-size:11.5px;letter-spacing:.08em}
.crumb{color:var(--muted);text-decoration:none;cursor:pointer;white-space:nowrap}
.crumb:hover{color:var(--ink)}
.crumbSep{color:var(--crumb-sep);font-size:9px}
.crumbHere{color:var(--ink);font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* the ‹ only appears in the collapsed form, where the trail becomes the
   single rung a thumb wants: the room you came out of */
.crumbBack{display:none}
/* Step back leaves the piece, not the room — a different verb, so it keeps
   the chip it has always had and simply sits under the trail. */
.stepback{top:72px}
.stepback.under{top:104px}
.turnbtns{position:absolute;right:46px;bottom:36px;display:flex;gap:12px;z-index:20}
.turnbtns button{width:44px;height:44px;border-radius:50%;border:1px solid var(--chrome-ink);background:rgba(var(--chrome-rgb),.7);font-size:16px;cursor:pointer;color:var(--chrome-ink)}
/* at either end of the hang the button goes quiet rather than doing nothing */
.turnbtns button[disabled]{opacity:.3;cursor:default}
.hint{position:absolute;left:0;right:0;bottom:22px;padding:0 24px;text-align:center;font-size:10px;letter-spacing:.12em;color:var(--muted);z-index:19;pointer-events:none}

/* ---------- work card ---------- */
.workcard{position:absolute;left:46px;bottom:44px;width:304px;z-index:14;background:rgba(253,252,248,.95);border:1px solid #ddd7c8;padding:22px 24px;box-shadow:0 24px 44px -22px rgba(52,44,26,.5);animation:tmpRise .5s ease both .3s;box-sizing:border-box}
.wcArtist{font-size:13px;font-weight:600}
.wcSub{margin-top:2px;font-size:9.5px;letter-spacing:.22em;text-transform:uppercase;color:#8d887b}
.wcTitle{margin-top:14px;font-family:Newsreader,serif;font-style:italic;font-size:20px;line-height:1.25}
.wcDims{margin-top:6px;font-size:11.5px;color:#8d887b}
.wcPrice{margin-top:14px;font-size:16px;font-weight:500}
.wcSoon{margin-top:14px;font-size:10.5px;line-height:1.7;color:#a09b8f}
.inquire{display:block;margin-top:14px;text-align:center;border:1px solid #26231d;color:#26231d;padding:12px 0;font-size:11px;letter-spacing:.16em;text-transform:uppercase;text-decoration:none}

/* ---------- cart drawer ---------- */
.dim{position:absolute;inset:0;background:rgba(38,35,29,.28);z-index:28;animation:tmpFade .2s ease}
.dimPage{position:absolute;inset:0;background:rgba(38,35,29,.3);z-index:28;animation:tmpFade .25s ease}
.drawer{position:absolute;top:0;right:0;bottom:0;width:360px;max-width:100%;background:#fdfcf8;border-left:1px solid #ddd7c8;padding:28px;display:flex;flex-direction:column;z-index:29;animation:tmpSlide .28s ease;box-sizing:border-box}
.drawerHead{display:flex;justify-content:space-between;align-items:center}
.drawerHead span{font-size:11px;letter-spacing:.22em;text-transform:uppercase}
.xClose{cursor:pointer;font-size:17px;text-decoration:none}
.cartEmpty{margin:32px 0 0;font-size:13px;color:#8d887b}
.cartItems{flex:1;overflow:auto;margin-top:22px;display:flex;flex-direction:column;gap:18px}
.cartRow{display:flex;gap:12px;align-items:center}
.cartThumb{width:54px;height:54px;flex:none;background-color:#ece8dd;background-size:cover;background-position:center;border:1px solid #ddd7c8}
/* a poem print has no photograph — its thumb is a tiny night panel */
.cartThumb.poem{background-image:linear-gradient(90deg,rgba(79,168,216,0),rgba(79,168,216,.85) 32%,#d9f2ff 50%,rgba(79,168,216,.85) 68%,rgba(79,168,216,0)),radial-gradient(90% 60% at 50% 90%,rgba(79,168,216,.28),rgba(79,168,216,0) 72%),linear-gradient(180deg,#0b1026,#050b18);background-size:78% 2px,100% 100%,100% 100%;background-position:50% 66%,50% 100%,0 0;background-repeat:no-repeat;border-color:#262e4a}
.cartMeta{flex:1;min-width:0}
.cartTitleLine{font-family:Newsreader,serif;font-style:italic;font-size:15px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cartArtist{margin-top:2px;font-size:10.5px;color:#8d887b}
.cartPrice{font-size:12.5px}
.cartRemove{cursor:pointer;color:#8d887b;font-size:15px;text-decoration:none}
.cartTotalRow{border-top:1px solid #ddd7c8;padding-top:16px;display:flex;justify-content:space-between;font-size:14px;font-weight:600}
.btn.checkout{margin-top:14px;padding:15px 0}
.cartFoot{margin-top:12px;font-size:9.5px;color:#b5b0a4}

/* ---------- about + contact modals ---------- */
/* THE PANEL ANIMATES WITHOUT LOSING ITS PLACE. The old entrance used tmpRise,
   which sets transform — and transform is also what centres this box. For the
   whole 450ms the panel therefore sat half its own width down and to the right
   of centre, then snapped into place when the animation ended. That is what
   "loads sloppy" was. The centring is now inside the keyframe, so it holds
   from the first frame to the last. */
@keyframes modalIn{
  from{opacity:0;transform:translate(-50%,calc(-50% + 14px))}
  to{opacity:1;transform:translate(-50%,-50%)}
}
.modal{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);background:#fdfcf8;border:1px solid #ddd7c8;z-index:29;animation:modalIn .45s ease;box-shadow:0 40px 80px -30px rgba(38,35,29,.5)}
/* ONE PANEL: the gallery's story, and how to reach someone about it. */
.modal.info{width:860px;max-width:92vw;max-height:86vh;overflow:auto;overscroll-behavior:contain;position:absolute}
/* The close sits over the picture, and the picture is whatever the gallery
   uploaded — so its contrast is not knowable in advance. It gets paper of its
   own rather than a guess about what it will land on. */
.infoX{position:absolute;top:16px;right:16px;z-index:2;line-height:1;width:30px;height:30px;
  display:flex;align-items:center;justify-content:center;border-radius:50%;
  background:rgba(253,252,248,.92);border:1px solid #ddd7c8;color:#26231d;font-size:16px}
.infoX:hover{background:#fdfcf8}
.infoGrid{display:grid;grid-template-columns:1fr 320px;align-items:stretch}
.infoText{padding:46px 46px 40px}
.modalHead{display:flex;justify-content:space-between;align-items:baseline}
.modalLabel{margin:0;font-size:9.5px;font-weight:400;letter-spacing:.3em;color:#98927f}
.aboutPara{margin:16px 0 0;font-family:Newsreader,serif;font-size:15.5px;line-height:1.75;color:#57534a;text-wrap:pretty}
.aboutPara.lead{margin:22px 0 0;font-size:17px;color:#46423a}
.aboutClose{margin:18px 0 0;font-family:Newsreader,serif;font-style:italic;font-size:15.5px;line-height:1.75;color:#46423a}
.aboutBtn{display:inline-block;margin-top:26px;cursor:pointer;background:#26231d;color:#fdfcf8;padding:13px 30px;font-size:11px;letter-spacing:.16em;text-transform:uppercase;text-decoration:none}
.infoImg{background-color:#ece8dd;background-size:cover;background-position:center;min-height:100%}
/* the two halves are one document, so the seam is a hairline rather than a
   second box — and the contact half is centred to read as an invitation */
.infoContact{border-top:1px solid #ece8dd;padding:38px 46px 44px;text-align:center;background:#faf8f2}
.contactHeadline{margin-top:20px;font-family:Newsreader,serif;font-style:italic;font-size:23px;line-height:1.45;color:#33302a;text-wrap:pretty;max-width:34em;margin-left:auto;margin-right:auto}
.contactEmail{display:inline-block;margin-top:24px;background:#26231d;color:#fdfcf8;padding:15px 36px;font-size:11px;letter-spacing:.16em;text-transform:uppercase;text-decoration:none}
.contactFollow{margin-top:22px;font-size:9px;letter-spacing:.3em;color:#98927f}
.contactIg{margin-top:8px;font-size:12px}
.contactIg a{color:#8d887b;text-decoration:none}
.contactIg a:hover{color:#26231d}

/* ---------- veil + intro ---------- */
#veil{position:absolute;inset:0;background:var(--t-void);z-index:34;transition:opacity .5s ease;pointer-events:none;opacity:0}
#intro{position:absolute;inset:0;background:#efece4;z-index:40;pointer-events:none;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px}
#intro.go{animation:tmpIntro 1.5s ease both}
.introTitle{font-size:15px;letter-spacing:.4em;font-weight:600;text-transform:uppercase;text-align:center;padding:0 20px}
.introSub{font-size:10px;letter-spacing:.34em;color:#98927f;text-transform:uppercase}
.introErr{max-width:520px;padding:0 24px;text-align:center;font-size:13px;line-height:1.6;color:#57534a}

/* ---------- media queries ---------- */
@media (max-width:768px) and (orientation:portrait){
  #stage{perspective:500px}
}
@media (max-width:768px){.readtext{right:16px;bottom:18px}
  /* on a phone the picture goes above the words rather than beside them —
     a 320px column next to text is neither a picture nor a margin */
  .infoGrid{grid-template-columns:1fr}
  .infoImg{min-height:210px;order:-1}
  .infoText{padding:34px 24px 30px}
  .infoContact{padding:30px 24px 36px}
  .contactHeadline{font-size:20px}
  .topbar{padding:14px 16px;gap:10px}
  .wordmark{font-size:8px;letter-spacing:.14em}
  .nav{gap:13px;font-size:10.5px}
  .nav a.cartlink{padding:6px 10px}
  .turnbtns{right:16px;bottom:18px}
  .hint{bottom:78px;font-size:9px;letter-spacing:.04em;padding:0 16px}
  .workcard{left:16px;right:16px;bottom:18px;width:auto;padding:18px 20px}
  .chip{left:16px !important}
  .crumbs{left:16px;font-size:10.5px;gap:6px;max-width:calc(100% - 32px)}
  /* standing at a piece on a phone the work card owns the bottom of the
     screen: the two buttons stack beside it and the words stand down —
     pinch and swipe are the two gestures a phone already teaches. */
  .turnbtns.at{flex-direction:column;gap:10px;right:16px;bottom:18px}
  .workcard.at{right:76px}
  .hint.at{display:none}
}
@media (max-width:768px) and (orientation:landscape){
  .hint{display:none}
}
@media (max-width:480px){
  .nav a[data-act="gomain"]{display:none}
  .nav{gap:12px;font-size:10px}
  .wordmark{font-size:7.5px;letter-spacing:.12em}
  /* no room for a trail: keep the one rung that is a way out — the room
     you came from — and let the back wall say where you are */
  .crumbs > *{display:none}
  .crumbs > .crumb.parent{display:inline;color:#57534a}
  .crumbs > .crumb.parent .crumbBack{display:inline}
}

/* Keep the frozen demo's controls usable when it opens full-screen on a
   phone. The projected 3D room stays unchanged behind this compact chrome. */
@media (max-width:480px){
  .topbar{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;padding:10px 16px}
  .wordmark{display:flex;align-items:center;min-height:44px;white-space:normal;font-size:8.5px;line-height:1.4}
  .nav{gap:8px;font-size:11.5px}
  .nav a{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;box-sizing:border-box}
  .nav a.cartlink{padding:6px 8px}
}
