:root{
  --bg:#F7F3ED;          /* warm paper ground */
  --card:#FFFFFF;
  --rule:#DDD6CA;
  --ink:#2A2724;
  --muted:#8C857B;
  --ochre:#B16220;       /* sampled from the artwork */
  --olive:#7B6021;
  --swatch:#EFEAE1;      /* ground behind the repeat */
  --rail: 520px;
}
*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;background:var(--bg);color:var(--ink);
  font-family:"Jost",system-ui,sans-serif;font-size:14px;font-weight:400;
  -webkit-font-smoothing:antialiased;
}
.app{display:flex;height:100vh;height:100dvh;overflow:hidden}

.rail{
  width:var(--rail);flex:0 0 var(--rail);
  background:var(--card);border-right:1px solid var(--rule);
  display:flex;flex-direction:column;overflow-y:auto;
}
.brand{padding:34px 26px 26px;border-bottom:1px solid var(--rule)}
.brand h1{
  margin:0;font-weight:300;font-size:20px;line-height:1;
  letter-spacing:.3em;text-transform:uppercase;color:var(--ink);
}
.brand p{margin:14px 0 0;color:var(--muted);font-size:12.5px;line-height:1.55;white-space:nowrap;font-weight:300}

.block{padding:24px 26px;border-bottom:1px solid var(--rule)}
.eyebrow{
  font-size:10px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--muted);margin:0 0 14px;display:block;font-weight:400;
}

.drop{
  border:1px solid var(--rule);background:var(--bg);
  padding:26px 16px;text-align:center;cursor:pointer;transition:border-color .18s,background .18s;
}
.drop:hover,.drop.over{border-color:var(--ochre);background:#FBF8F3}
.drop strong{display:block;font-weight:400;margin-bottom:6px;letter-spacing:.04em}
.drop span{color:var(--muted);font-size:12px;font-weight:300}
/* Two sets of wording for the drop zone: a phone has no drag and drop and no ⌘V, but its
   file picker offers the camera.

   `pointer:coarse` alone, deliberately. This was `(hover:none) and (pointer:coarse)` and
   Android users reported getting the desktop wording — several Android browsers, Samsung
   Internet and the in-app webviews most of all, report `hover:hover`, which breaks the AND
   even though the pointer is reported correctly. `pointer` describes the *primary* input,
   so a touchscreen laptop with a mouse still reads `fine` and keeps the desktop wording,
   which is right: it can drag and paste. The width clause is a backstop for any device
   that gets `pointer` wrong too — a phone is narrow whatever it claims about itself. No
   min-height on that clause, unlike the layout queries: a phone held sideways is short and
   still a phone. The cost is that a narrow desktop window gets the touch wording, which is
   a far cheaper mistake than a phone being told to press ⌘V. */
.drop .touch{display:none}
@media (pointer:coarse), (max-width:820px){
  .drop .desk{display:none}
  .drop strong.touch{display:block}
  .drop span.touch{display:inline}
}
.filecard{display:none;align-items:center;gap:14px}
.filecard.on{display:flex}
.thumb{width:54px;height:54px;flex:0 0 54px;border:1px solid var(--rule);background:var(--swatch) center/cover no-repeat}
.fileinfo{min-width:0;flex:1}
/* name and size share one line, the size right-aligned against the far edge: it is short
   and fixed, so it keeps the width it needs and the name takes the rest, truncating
   rather than wrapping */
.fileline{display:flex;align-items:baseline;gap:9px;min-width:0;margin-bottom:5px}
.filename{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:13px}
.dims{flex:0 0 auto;margin-left:auto;font-size:11px;color:var(--muted);letter-spacing:.08em;font-weight:300}
.link{background:none;border:0;padding:0;color:var(--ochre);font:inherit;font-size:12px;cursor:pointer;
  text-decoration:none;border-bottom:1px solid currentColor;letter-spacing:.06em}
.link:hover{color:var(--ink)}

.grow{flex:1 1 auto;display:flex;flex-direction:column}
.modes{display:grid;grid-template-columns:repeat(4,1fr);gap:11px;flex:1 1 auto;grid-auto-rows:minmax(min-content,1fr)}
.mode{
  position:relative;border:1px solid var(--rule);background:var(--card);
  padding:0;cursor:pointer;text-align:left;color:inherit;font:inherit;transition:border-color .18s;
}
.mode:hover{border-color:var(--muted)}
.mode:focus-visible{outline:2px solid var(--ochre);outline-offset:2px}
.mode{display:flex;flex-direction:column}
.mode .sw{flex:1 1 auto;min-height:38px;background:var(--swatch) center/auto repeat}
.mode .nm{flex:0 0 auto;padding:9px 10px 10px;font-size:11px;line-height:1.25;
  letter-spacing:.14em;text-transform:uppercase;border-top:1px solid var(--rule)}
.mode[aria-pressed="true"]{border-color:var(--ochre)}
.mode[aria-pressed="true"] .nm{background:var(--ochre);color:#fff;border-top-color:var(--ochre)}

.counts{display:grid;grid-template-columns:repeat(5,1fr);gap:8px}
.count{
  border:1px solid var(--rule);background:var(--card);color:var(--muted);
  font:inherit;font-size:12px;letter-spacing:.06em;padding:11px 0;text-align:center;
  cursor:pointer;transition:all .18s;font-variant-numeric:tabular-nums;
}
.count:hover{border-color:var(--ochre);color:var(--ink)}
.count[aria-pressed="true"]{background:var(--ochre);border-color:var(--ochre);color:#fff}
.count:focus-visible{outline:2px solid var(--ochre);outline-offset:2px}

.btn{
  width:100%;padding:15px;border:0;background:var(--ink);color:#fff;
  font-family:inherit;font-weight:400;font-size:11px;
  letter-spacing:.22em;text-transform:uppercase;cursor:pointer;transition:background .18s;
}
.btn:hover{background:var(--ochre)}
.btn:disabled{background:var(--bg);color:var(--muted);cursor:not-allowed}
.btn:focus-visible{outline:2px solid var(--ochre);outline-offset:2px}
.foot{margin-top:auto}      /* download always sits at the bottom of the rail */

/* the maker's credit — deliberately quiet: it sits under the download button and
   should read as a footnote, not as another control */
.credit{
  margin:14px 0 0;text-align:center;
  font-size:10px;letter-spacing:.14em;color:var(--muted);font-weight:300;
}
.credit a{color:inherit;text-decoration:none;border-bottom:1px solid var(--rule);transition:color .18s,border-color .18s}
.credit a:hover{color:var(--ochre);border-bottom-color:var(--ochre)}
.credit a:focus-visible{outline:2px solid var(--ochre);outline-offset:2px}

/* drawer chrome — inert on desktop: the grab bar is hidden and the wrappers are
   display:contents, so the rail lays out exactly as if they weren't there */
.grab{display:none;width:100%;border:0;background:var(--card);padding:14px 0;cursor:pointer;touch-action:none}
.grabpill{display:block;width:44px;height:4px;margin:0 auto;background:var(--rule);border-radius:2px;transition:background .18s}
.grab:hover .grabpill{background:var(--ochre)}
.grab:focus-visible{outline:2px solid var(--ochre);outline-offset:-2px}
.drawerbody,.drawerinner{display:contents}

.stage{flex:1;position:relative;min-width:0;background:var(--bg);overflow:hidden}
.surface{position:absolute;inset:-40%;background:var(--swatch) center/auto repeat;transform-origin:center}
.empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;text-align:center;padding:24px}
.empty[hidden]{display:none}
.empty p{
  font-size:11px;letter-spacing:.34em;text-transform:uppercase;
  color:var(--muted);margin:0;font-weight:300;
}

/* ---------- cropper ---------- */
.cropper{position:fixed;inset:0;z-index:20;background:var(--bg);display:flex;flex-direction:column}
.cropper[hidden]{display:none}
.crophead{
  display:flex;align-items:center;gap:26px;flex-wrap:wrap;
  padding:20px 26px;border-bottom:1px solid var(--rule);background:var(--card);
}
.ratios{display:flex;gap:8px;margin-right:auto}
.ratio{
  border:1px solid var(--rule);background:var(--card);color:var(--muted);
  font:inherit;font-size:10px;letter-spacing:.18em;text-transform:uppercase;
  padding:8px 14px;cursor:pointer;transition:all .18s;
}
.ratio:hover{border-color:var(--ochre);color:var(--ink)}
.ratio[aria-pressed="true"]{background:var(--ochre);border-color:var(--ochre);color:#fff}
.ratio:focus-visible{outline:2px solid var(--ochre);outline-offset:2px}
.cropacts{display:flex;align-items:center;gap:20px}
.btnsm{width:auto;padding:12px 24px}
.cropstage{flex:1;display:flex;align-items:center;justify-content:center;padding:32px;overflow:hidden}
.cropwrap{position:relative;line-height:0;touch-action:none}
.cropwrap img{display:block;max-width:100%;max-height:100%;user-select:none;-webkit-user-drag:none}
.cropbox{
  position:absolute;box-sizing:border-box;border:1px solid #fff;cursor:move;
  box-shadow:0 0 0 9999px rgba(42,39,36,.55);
}
.hdl{position:absolute;width:16px;height:16px;background:#fff;border:1px solid var(--ochre)}
.hdl.nw{left:-8px;top:-8px;cursor:nwse-resize}
.hdl.ne{right:-8px;top:-8px;cursor:nesw-resize}
.hdl.sw{left:-8px;bottom:-8px;cursor:nesw-resize}
.hdl.se{right:-8px;bottom:-8px;cursor:nwse-resize}
.cropfoot{
  margin:0;padding:16px 26px;border-top:1px solid var(--rule);background:var(--card);
  font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);font-weight:300;
}

@media (max-width:820px) and (min-height:500px){
  .app{flex-direction:column-reverse}
  /* the rail takes exactly the height its content needs... */
  .rail{width:100%;flex:0 0 auto;border-right:0;border-top:0}
  /* ...and the preview takes everything that is left, so nothing scrolls */
  .stage{flex:1 1 auto;min-height:110px}
  /* the rail is a pull-up drawer: the grab bar, or a tap anywhere on the preview,
     toggles it. 1fr→0fr animates to natural height with no measuring;
     app.js gates its toggling on this same media query — change them together */
  .grab{display:block}
  .drawerbody{display:grid;grid-template-rows:1fr;transition:grid-template-rows .2s ease}
  .drawerinner{display:block;overflow:hidden;min-height:0}
  .app.closed .drawerbody{grid-template-rows:0fr}
  /* content stays visible while the drawer shrinks, vanishes (and leaves the tab
     order) once it lands; reopening shows it immediately. The delay tracks the
     duration above, and app.js's settle() fallback timer has to outlast both */
  .app.closed .drawerinner{visibility:hidden;transition:visibility 0s .2s}
  /* while a finger is on the grab bar the drawer tracks it: no transition to fight the
     drag, and the content stays visible even when the pull starts from closed */
  .app.dragging .drawerbody{transition:none}
  .app.dragging .drawerinner{visibility:visible;transition:none}
  /* the stacked layout is fighting for height, so trim chrome that earns nothing here.
     No section rules at all: the eyebrows already say where each group starts, and the
     preview's colour marks the drawer's edge far better than a hairline. The picker
     announces itself, so it loses its label too. Every pixel saved goes to the preview.
     Control borders — the drop zone, the mode and count buttons — are boxes, not rules,
     and stay. */
  .brand,.block{border-bottom:0}
  .brand{padding:18px 20px 14px}
  /* no rule and no label above it any more, so its top padding is only buying air the
     strapline's line-height has already paid for — the brand's own padding is the gap.
     Two classes deep so the .block padding shorthand later in this query cannot undo it */
  .block.upload{padding-top:0}
  .upload .eyebrow{display:none}
  .credit{display:none}          /* the maker's credit is desktop-only — no room here */
  .brand p{margin-top:9px;font-size:min(12.5px,3.3vw)}   /* keeps the one-liner on narrow phones */
  .block{padding:14px 20px}
  .drop{padding:16px 12px}
  .grow{display:block}
  .modes{grid-template-columns:repeat(4,1fr);gap:6px;grid-auto-rows:auto}
  .mode .sw{flex:none;height:52px}
  .mode .nm{padding:5px 4px 6px;font-size:8.5px;letter-spacing:.06em;text-align:center}
  .counts{gap:6px}
  .count{padding:10px 0}
  .btn{padding:13px}
  .eyebrow{margin-bottom:10px}
}

/* shorter handsets — trim the rail so the preview keeps a usable share */
@media (max-width:820px) and (min-height:500px) and (max-height:780px){
  .brand{padding:14px 18px 12px}
  .brand p{margin-top:7px}
  .block{padding:11px 18px}
  .mode .sw{height:44px}
  .count{padding:9px 0}
  .btn{padding:12px}
}

@media (max-width:820px) and (min-height:500px) and (max-height:700px){
  .block{padding:10px 18px}
  .mode .sw{height:40px}
}
/* short desktop windows — the padding is the first thing to go */
@media (min-width:821px) and (max-height:790px){
  .brand{padding:24px 26px 20px}
  .block{padding:18px 26px}
}

/* laptop windows shorter still — trim the padding everywhere */
@media (min-width:821px) and (max-height:660px){
  .brand{padding:16px 26px 14px}
  .block{padding:12px 26px}
  .drop{padding:16px 12px}
  .eyebrow{margin-bottom:8px}
  .btn{padding:12px}
  .count{padding:9px 0}
  .mode .sw{min-height:30px}
  .credit{margin-top:10px}
}

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