/*
  Visual direction: the packing table.
  Type is monospace wherever the page shows data a seller has to scan - counts,
  order IDs, page numbers, sizes - because that is the vernacular of manifests,
  thermal receipts and barcodes. Prose is set in the system sans.
  The one bold element is the crop-mark frame: four registration ticks that
  bracket the drop zone and every detected label. It is the thing the tool does.
*/

/*
 * The hidden attribute must always win.
 *
 * The browser's own rule is `[hidden] { display: none }`, which any class
 * setting `display` outranks - so an element marked hidden in the markup stays
 * on screen the moment it also carries a layout class. That put a receipt with
 * em-dashes where the plan name should be in front of a seller who had just
 * paid, and it is the same trap as an invisible overlay that still swallows
 * taps. There are 166 display rules in this stylesheet; auditing them one by
 * one would fix today's instance and none of the next ones.
 *
 * !important is right here. This is not styling, it is the meaning of the
 * attribute, and there is no case where markup says hidden and we want it
 * seen. Anything that needs to animate out uses a class instead.
 */
[hidden] { display: none !important; }


:root {
  --paper:   #e9edf0;
  --card:    #ffffff;
  --ink:     #0d1b2a;
  --ink-2:   #5a6b7b;
  --ink-3:   #8c9ba8;
  --rule:    #c9d3db;
  --rule-2:  #dde4e9;
  --shimmer: rgba(255, 255, 255, 0.7);
  --signal:  #d62246;
  --ok:      #1e7a5a;
  --warn:    #9a6700;

  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;

  --step: 4px;
  --radius: 3px;
}

/*
  The theme does not follow the operating system. Sellers print from this in
  daylight and the tool pages are documents, so light is the default and dark is
  an explicit choice, remembered per browser. All dark values live under
  [data-theme="dark"] below.
*/

/* Explicit theme choice beats the OS preference, in both directions. The same
   tokens as above, so components never need to know which theme is active. */
:root[data-theme="dark"] {
    --paper:  #0b1218;
    --card:   #131c24;
    --ink:    #e6edf3;
    --ink-2:  #9fb0bd;
    --ink-3:  #6b7c8a;
    --rule:   #2a3742;
    --rule-2: #1e2933;
    --shimmer: rgba(255, 255, 255, 0.07);
    --signal: #ff5a72;
    --ok:     #4bbf8f;
    --warn:   #d4a017;
}
:root[data-theme="light"] {
  --paper:   #e9edf0;
  --card:    #ffffff;
  --ink:     #0d1b2a;
  --ink-2:   #5a6b7b;
  --ink-3:   #8c9ba8;
  --rule:    #c9d3db;
  --rule-2:  #dde4e9;
  --shimmer: rgba(255, 255, 255, 0.7);
  --signal:  #d62246;
  --ok:      #1e7a5a;
  --warn:    #9a6700;

  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;

  --step: 4px;
  --radius: 3px;
}

* { box-sizing: border-box; }

/* A panel wider than the screen must not make the whole page scroll
   sideways - on a phone that reads as the layout being broken. */
body { overflow-x: clip; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* ---------- structural type ---------- */

.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  display: flex;
  align-items: center;
  gap: 8px;
}
.eyebrow::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule);
}
.eyebrow .num { color: var(--signal); font-weight: 700; }

.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* ---------- shell ---------- */

.masthead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 18px 24px;
  border-bottom: 1px solid var(--rule);
  background: var(--card);
}

.wordmark {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin: 0;
}
.wordmark .bars {
  color: var(--signal);
  letter-spacing: -1px;
  margin-left: 6px;
}

.masthead p { margin: 0; font-size: 13px; color: var(--ink-2); }

.layout {
  display: grid;
  grid-template-columns: 360px minmax(0, 1fr);
  gap: 0;
  align-items: stretch;
  min-height: calc(100vh - 140px);
}

.controls {
  border-right: 1px solid var(--rule);
  background: var(--card);
  padding: 20px 22px 40px;
  /* Full height and pinned: the rail should read as a side of the app, not as
     a card that runs out partway down the page. */
  align-self: start;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.stage { padding: 22px 26px 40px; min-width: 0; }

.block + .block { margin-top: 26px; }
.block > .eyebrow { margin-bottom: 12px; }

/* ---------- crop-mark frame: the signature ---------- */

.cropframe { position: relative; }
.cropframe::before,
.cropframe::after,
.cropframe > .tick-b::before,
.cropframe > .tick-b::after {
  content: "";
  position: absolute;
  width: 14px;
  height: 14px;
  border: 2px solid var(--signal);
  transition: inset 160ms ease, opacity 160ms ease;
}
.cropframe::before      { top: -1px; left: -1px;  border-right: 0; border-bottom: 0; }
.cropframe::after       { top: -1px; right: -1px; border-left: 0;  border-bottom: 0; }
.cropframe > .tick-b::before { bottom: -1px; left: -1px;  border-right: 0; border-top: 0; }
.cropframe > .tick-b::after  { bottom: -1px; right: -1px; border-left: 0;  border-top: 0; }

/* ---------- drop zone ---------- */

.dropzone {
  aspect-ratio: 4 / 6;
  width: min(340px, 100%);
  margin: 4vh auto 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
  padding: 24px;
  background: var(--card);
  border: 1px dashed var(--rule);
  cursor: pointer;
}
.dropzone:hover, .dropzone.is-over { border-color: var(--signal); }
.dropzone.is-over::before, .dropzone.is-over::after,
.dropzone.is-over > .tick-b::before, .dropzone.is-over > .tick-b::after { inset: auto; }
.dropzone.is-over::before { top: 7px; left: 7px; }
.dropzone.is-over::after  { top: 7px; right: 7px; }
.dropzone.is-over > .tick-b::before { bottom: 7px; left: 7px; }
.dropzone.is-over > .tick-b::after  { bottom: 7px; right: 7px; }

.dropzone h2 {
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin: 0;
}
.dropzone p { margin: 0; font-size: 13px; color: var(--ink-2); max-width: 24ch; }
.dropzone .ratio {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.1em;
}

.stage-intro { max-width: 46ch; margin: 0 auto; text-align: center; }
.stage-intro h1 {
  font-family: var(--mono);
  font-size: clamp(20px, 3vw, 28px);
  line-height: 1.25;
  letter-spacing: -0.01em;
  margin: 0 0 10px;
}
.stage-intro p { color: var(--ink-2); margin: 0; }

/* ---------- file list ---------- */

.filelist { list-style: none; margin: 0; padding: 0; }
.filelist li {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--rule-2);
  font-size: 13px;
}
.filelist .fname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.filelist .fpages { font-family: var(--mono); font-size: 11px; color: var(--ink-3); }

/* ---------- settings ---------- */

.setting {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 7px 0;
}
.setting label { font-size: 14px; cursor: pointer; }
.setting .hint { display: block; font-size: 12px; color: var(--ink-3); margin-top: 1px; }

/*
 * A .setting whose label needs something under it as well - the crop page's
 * "add this run to order scan check", where the full list of what leaves the
 * browser sits in a <details> that must not be inside the <label>, or its
 * summary would tick the box.
 */
.setting__body { min-width: 0; }
.carry-what > summary {
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
  margin-top: 4px;
  width: fit-content;
}
.carry-what > summary:hover { color: var(--ink); }
.carry-what .hint { margin-top: 4px; }
.setting input[type="checkbox"] { margin-top: 3px; accent-color: var(--signal); width: 15px; height: 15px; }

.setting-row { padding: 7px 0; }
.setting-row > span { display: block; font-size: 14px; margin-bottom: 5px; }

/*
 * `date` and `url` are in this list for the same reason `text` is: they sit in
 * the same form rails. Left out, a date field kept the browser's own look -
 * intrinsic width, no border, its own background - and was the one control on
 * the page that did not look like one.
 */
select, input[type="text"], input[type="number"],
input[type="date"], input[type="url"] {
  width: 100%;
  font: inherit;
  font-size: 14px;
  padding: 7px 9px;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}
/*
 * The theme here is an explicit choice, not the OS preference - so the parts of
 * a date field the browser draws itself have to be told which one is active.
 * The calendar button and the picker come from color-scheme and not from our
 * `color`, so without this a dark page gets a black icon on a dark field.
 *
 * line-height is pinned because a date field's internal text box ignores
 * `normal` and comes out a few pixels shorter than the text inputs beside it.
 */
input[type="date"] { color-scheme: light; line-height: 1.25; }
:root[data-theme="dark"] input[type="date"] { color-scheme: dark; }
/*
 * :required gets no styling of its own, and :invalid gets none either.
 *
 * Safari's UA stylesheet draws a red glow around an empty required field from
 * the first paint - before anyone has touched it, which reads as an error
 * nobody made yet. Every error on this site is already said in words, through
 * .l-notice or a field's own .l-hint--bad, never through the browser's own
 * red ring - so this is a reset, not a design choice being overridden.
 */
input:invalid, select:invalid, textarea:invalid { box-shadow: none; }

/* ---------- buttons ---------- */

.btn {
  /*
   * inline-flex, because half of these are anchors.
   *
   * .btn set padding and .btn--full set a width, but nothing ever set a
   * display - so on a <button>, which is inline-block already, it worked, and
   * on an <a>, which is not, the width was ignored, the vertical margin was
   * ignored, and the padding was painted without making the line box any
   * taller. Seventy-eight anchors across thirty-nine pages were drawn that way
   * and all of them looked passable, because a landing page puts one button on
   * a line with room around it. app.html stacks two full-width ones, and there
   * the two boxes overlapped: "Android - get it on Google Play" was printed
   * through "iPhone - get it on the App Store".
   *
   * flex rather than inline-block so an icon beside a label is centred and
   * spaced by the gap, which is what download-fab.js was reaching for with its
   * own copy of these rules.
   */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  /* Same root cause as the display: an anchor brings its own underline, and
     every one of these was drawn with one through the label. */
  text-decoration: none;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 11px 16px;
  border: 1px solid var(--ink);
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--card);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.btn:hover:not(:disabled) { background: var(--signal); border-color: var(--signal); color: #fff; }
.btn:disabled { opacity: 0.35; cursor: not-allowed; }
.btn--full { width: 100%; }
/* Two stacked full-width buttons: the gap belongs to the group, not to an
   inline style on the second one. */
.btn--stack { display: grid; gap: 10px; }
.btn--quiet {
  background: transparent;
  color: var(--ink-2);
  border-color: var(--rule);
}
.btn--quiet:hover:not(:disabled) { color: var(--signal); border-color: var(--signal); background: transparent; }
.btn--tiny { padding: 4px 8px; font-size: 10px; }

:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }

/* ---------- stats strip ---------- */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  margin-bottom: 22px;
}
.stat { background: var(--card); padding: 11px 13px; }
.stat b {
  display: block;
  font-family: var(--mono);
  font-size: 21px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.stat span {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ---------- proof sheet ---------- */

.proof { display: block; }
.proofgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 18px;
}
.proofmore { display: block; margin: 20px auto 0; }
.proofmore.hidden { display: none; }

.thumb { background: var(--card); border: 1px solid var(--rule); padding: 9px; }
/* overflow:hidden is load-bearing: .cropmark dims the page with a 9999px
   box-shadow, which without clipping would darken the whole viewport once per
   thumbnail. */
.thumb .shot { position: relative; background: #fff; line-height: 0; overflow: hidden; }
.thumb canvas { width: 100%; height: auto; display: block; }
.thumb .meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 6px;
  margin-top: 7px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.badge { padding: 1px 5px; border: 1px solid currentColor; border-radius: 2px; }
.badge--label    { color: var(--ok); }
.badge--invoice  { color: var(--ink-3); }
.badge--combined { color: var(--warn); }
.badge--blank    { color: var(--signal); }

/* crimson rectangle showing exactly what will be kept */
.cropmark {
  position: absolute;
  border: 1.5px solid var(--signal);
  pointer-events: none;
  box-shadow: 0 0 0 9999px rgba(13, 27, 42, 0.42);
}

/* ---------- manual crop editor ---------- */

.cropedit { background: var(--card); border: 1px solid var(--rule); padding: 16px; margin-bottom: 22px; }
.cropedit .surface {
  position: relative; display: inline-block; line-height: 0;
  cursor: crosshair; user-select: none; overflow: hidden;
}
.cropedit canvas { display: block; max-width: 100%; height: auto; }
.cropedit .hintbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-top: 12px;
  font-size: 13px; color: var(--ink-2);
}

/* ---------- notices ---------- */

.notice {
  border-left: 3px solid var(--signal);
  background: var(--card);
  padding: 10px 13px;
  font-size: 13px;
  margin-bottom: 16px;
}
.notice--ok { border-left-color: var(--ok); }

.progress { height: 3px; background: var(--rule); overflow: hidden; margin-top: 14px; }
.progress i { display: block; height: 100%; background: var(--signal); width: 0; transition: width 140ms linear; }
.progress-label { font-family: var(--mono); font-size: 11px; color: var(--ink-3); margin-top: 6px; letter-spacing: 0.06em; }

.privacy {
  font-size: 12px;
  color: var(--ink-3);
  border-top: 1px solid var(--rule-2);
  margin-top: 22px;
  padding-top: 12px;
}
.privacy b { color: var(--ink-2); font-weight: 600; }

/*
 * A link in the small print, styled - because nothing was styling it.
 *
 * .privacy is prose and some of it carries links: account.html points at Low
 * stock alert from here, and dashboard.html points at Order scan check. Both
 * were getting the browser's default blue, which is 2.01:1 against the dark
 * ground where 4.5:1 is the requirement - unreadable on exactly the theme most
 * of these pages are read in.
 *
 * --ink-2 rather than --signal: it clears 4.5:1 on both grounds in both themes
 * (8.46 and 7.73 dark, 4.66 and 5.49 light), where --signal is 4.27 against
 * light paper and would have been a new marginal case. The signal goes on the
 * underline and the hover instead, which is the pattern `.cat a` and
 * `.toolhead__crumbs a` already set - a link here should read as part of the
 * sentence it sits in, not as a button.
 */
.privacy a {
  color: var(--ink-2);
  text-decoration: none;
  border-bottom: 1px solid var(--signal);
}
.privacy a:hover { color: var(--signal); }

/* A saved packing day that lost the file behind it. Same weight as the rest of
   the panel's small print, but coloured, because it is the one line here that
   asks the seller to do something. */
.privacy--warn {
  color: var(--warn);
  border-top-color: var(--warn);
  margin-top: 12px;
}

.hidden { display: none !important; }

@media (max-width: 860px) {
  .layout { grid-template-columns: 1fr; }
  .controls { position: static; max-height: none; border-right: 0; border-bottom: 1px solid var(--rule); }
}

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

/* ============================================================
   Site shell: masthead, menu, home, tools directory
   ============================================================ */

.masthead {
  position: relative;
  z-index: 20;
  gap: 8px 24px;
  align-items: center;
}

.brand { text-decoration: none; color: inherit; flex: none; }
.brand .wordmark { display: inline-flex; align-items: baseline; }

/* The old masthead menu (.menu / .menutoggle / .menupanel) was replaced by the
   l-* header built in ui/nav.js. Its rules are gone; the mobile drawer now
   lives with the rest of that header in landing.css. */
/* ---------- home ---------- */

.home { padding: 0 24px 72px; }

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 48px;
  align-items: center;
  padding: 56px 0 44px;
  border-bottom: 1px solid var(--rule);
}
@media (max-width: 860px) { .hero { grid-template-columns: 1fr; gap: 32px; } }

.hero h1 {
  font-family: var(--mono);
  font-size: clamp(26px, 4.2vw, 44px);
  line-height: 1.15;
  letter-spacing: -0.02em;
  margin: 0 0 14px;
  max-width: 18ch;
}
.hero h1 em { font-style: normal; color: var(--signal); }
.hero p { margin: 0 0 22px; font-size: 16px; color: var(--ink-2); max-width: 52ch; }
.hero .cta { display: flex; gap: 10px; flex-wrap: wrap; }

/* A 4:6 label standing in for the thing the whole site is about. */
.herolabel {
  width: 208px;
  aspect-ratio: 4 / 6;
  background: var(--card);
  border: 1px solid var(--rule);
  padding: 18px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.herolabel .rule { height: 1px; background: var(--rule-2); }
.herolabel .line { height: 6px; background: var(--rule-2); border-radius: 1px; }
.herolabel .line.short { width: 55%; }
.herolabel .line.mid { width: 78%; }
.herolabel .barcode { display: flex; align-items: flex-end; gap: 2px; height: 52px; margin-top: auto; }
.herolabel .barcode i { display: block; flex: 1; background: var(--ink); height: 100%; }
.herolabel .barcode i:nth-child(3n) { opacity: 0.35; }
.herolabel .barcode i:nth-child(4n) { opacity: 0.7; }
.herolabel .cap {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.catgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  margin-top: 40px;
}
.cat { background: var(--card); padding: 20px 20px 22px; }
.cat h2 {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin: 0 0 4px;
}
.cat > p { margin: 0 0 14px; font-size: 13px; color: var(--ink-3); }
.cat ul { list-style: none; margin: 0; padding: 0; }
.cat li { padding: 4px 0; font-size: 13.5px; border-bottom: 1px solid var(--rule-2); }
.cat li:last-child { border-bottom: 0; }
.cat a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--signal); }
.cat a:hover { color: var(--signal); }
.cat .muted { color: var(--ink-3); }
.cat .more { font-family: var(--mono); font-size: 11px; color: var(--ink-3); padding-top: 8px; display: block; }

/* ---------- tools directory ---------- */

.directory { padding: 28px 24px 72px; }
.directory > h1 {
  font-family: var(--mono);
  font-size: clamp(22px, 3vw, 30px);
  letter-spacing: -0.01em;
  margin: 0 0 6px;
}
.directory > p.lede { margin: 0 0 30px; color: var(--ink-2); max-width: 62ch; }

.dirsection { margin-bottom: 34px; }
.dirsection > p { margin: 0 0 12px; font-size: 13px; color: var(--ink-3); }

.toolgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(238px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
}
.toolcard {
  background: var(--card);
  padding: 14px 15px 16px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  text-decoration: none;
  color: inherit;
  border-left: 2px solid transparent;
}
a.toolcard:hover { border-left-color: var(--signal); }
.toolcard h3 { margin: 0; font-size: 14.5px; font-weight: 600; }
.toolcard p { margin: 0; font-size: 12.5px; color: var(--ink-3); line-height: 1.45; }
.toolcard.is-soon h3 { color: var(--ink-2); }
.toolcard .tag {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-top: auto;
  padding-top: 8px;
}
.toolcard.is-live .tag { color: var(--ok); }
.toolcard .tag.needs-server { color: var(--warn); }



/* settings: inline number field and pasted-list box */
.setting-row--inline {
  display: grid;
  grid-template-columns: 1fr 72px auto;
  align-items: center;
  gap: 8px;
}
.setting-row--inline > span:first-child { margin-bottom: 0; }
.setting-row--inline input { width: 100%; }
.setting-row--inline .suffix { font-size: 13px; color: var(--ink-3); }
.setting-row--inline .hint { grid-column: 1 / -1; }

.setting-row textarea {
  width: 100%;
  font: inherit;
  font-family: var(--mono);
  font-size: 12px;
  padding: 7px 9px;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  resize: vertical;
}

/* a setting this document has no data for */
.setting.is-unavailable label { color: var(--ink-3); cursor: not-allowed; }
.setting.is-unavailable .hint { color: var(--warn); }

/* ---------- theme toggle ---------- */

.themetoggle {
  width: 36px;
  height: 36px;
  flex: none;
  display: grid;
  place-items: center;
  padding: 0;
  cursor: pointer;
  color: var(--ink-2);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 8px;
  transition: color 120ms ease, border-color 120ms ease;
}
.themetoggle:hover { color: var(--signal); border-color: var(--signal); }
.themetoggle svg { width: 17px; height: 17px; }

/*
 * Light, dark, system - three radio options rather than a flip.
 *
 * A flip cannot express the third one: there is no order in which the three
 * follow each other that anybody could predict, so pressing twice to get back
 * where you were stops being true the moment "system" is in the cycle.
 */
.themepick { position: relative; display: inline-flex; }
.thememenu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 80;
  min-width: 132px;
  display: grid;
  gap: 1px;
  padding: 5px;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: 0 8px 22px rgba(13, 27, 42, 0.14);
}
.themeopt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 7px 9px;
  font: inherit;
  font-size: 13px;
  text-align: left;
  color: var(--ink-2);
  background: transparent;
  border: 0;
  border-radius: var(--radius);
  cursor: pointer;
}
.themeopt:hover { background: var(--rule-2); color: var(--ink); }
.themeopt.is-on { color: var(--signal); font-weight: 650; }
/* The tick is drawn from the state, so it cannot disagree with aria-checked. */
.themeopt.is-on::after { content: "\2713"; font-family: var(--mono); }

/* ---------- recent files ---------- */

.histlist { list-style: none; margin: 0; padding: 0; }
.histlist li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 0;
  border-bottom: 1px solid var(--rule-2);
}
.histlist li:last-child { border-bottom: 0; }

.histmain { min-width: 0; flex: 1; }
.histname {
  display: block;
  font-size: 13px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.histmeta {
  display: block;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
  margin-top: 2px;
}
/* Today / Yesterday / Earlier, between the rows they head. */
.histday {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 8px 0 2px;
}
.histday:first-of-type { padding-top: 0; }

.histactions, .histask { display: flex; align-items: center; gap: 4px; flex: none; }

/*
 * The file that was just saved, at the top of the working area.
 *
 * Same two actions as a row in the recent-files panel, in the one place the
 * seller is already looking when the export lands - the panel itself sits
 * below every setting the tool has, which on the cropper is several screens
 * away from the button that made the file.
 */
.lastfile {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  margin-bottom: 12px;
  border: 1px solid var(--ok);
  border-radius: var(--radius);
  background: var(--card);
}
.lastfile__main { min-width: 0; flex: 1 1 auto; }
.lastfile__tag {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ok);
  margin-right: 6px;
}
.lastfile__name {
  font-size: 13px;
  font-weight: 600;
  overflow-wrap: anywhere;
}
.lastfile__meta {
  display: block;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
  margin-top: 2px;
}

/*
 * Icon buttons, sized for a thumb rather than a mouse. 36px is the smallest
 * target that is reliably hit on a phone; the glyph inside stays small so the
 * row does not grow with it.
 */
.histbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: none;
  color: var(--ink-2);
  cursor: pointer;
}
.histbtn svg { width: 17px; height: 17px; }
.histbtn:hover { color: var(--ink); border-color: var(--rule); background: var(--paper); }
.histbtn:focus-visible { outline: 2px solid var(--signal); outline-offset: 1px; }
.histbtn[disabled] { opacity: 0.45; cursor: default; }
.histbtn--risk:hover { color: var(--signal); border-color: var(--signal); }

.histask__q {
  font-size: 12px;
  color: var(--ink-2);
  margin-right: 2px;
}

.linkish {
  font: inherit;
  font-size: inherit;
  padding: 0;
  border: 0;
  background: none;
  color: var(--signal);
  text-decoration: underline;
  cursor: pointer;
}
.linkish:hover { color: var(--ink); }

/* ---------- floating download button ---------- */

/*
 * Back in the corner it was always meant to have.
 *
 * It was lifted to 90px to clear the chat bubble, which sat on top of it. The
 * bubble is in the header now, so the corner is free and the one control that
 * produces the file the seller came for can have it.
 */
.fab {
  position: fixed;
  right: 22px;
  bottom: 22px;
  z-index: 60;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 14px 20px;
  cursor: pointer;
  color: #fff;
  background: var(--signal);
  border: 1px solid var(--signal);
  border-radius: 100px;
  box-shadow: 0 6px 16px rgba(13, 27, 42, 0.18), 0 18px 40px rgba(13, 27, 42, 0.16);
  transition: transform 140ms ease, opacity 140ms ease, background 140ms ease;
}
.fab svg { width: 17px; height: 17px; }
.fab:hover:not(.is-off) { transform: translateY(-2px); background: var(--ink); border-color: var(--ink); }

/* Present but obviously inert until the page has produced something. */
.fab.is-off {
  cursor: not-allowed;
  opacity: 0.45;
  color: var(--ink-2);
  background: var(--card);
  border-color: var(--rule);
  box-shadow: 0 2px 8px rgba(13, 27, 42, 0.1);
}

@media (max-width: 620px) {
  .fab { right: 14px; bottom: 14px; padding: 13px 17px; font-size: 11px; }
}
@media (prefers-reduced-motion: reduce) {
  .fab { transition: none; }
  .fab:hover:not(.is-off) { transform: none; }
}


/* ---------- tool header ---------- */

.toolhead {
  background: var(--card);
  border-bottom: 1px solid var(--rule);
}
/*
  One row, not three stacked blocks. The tool is what the page is for; the
  header only has to say which tool this is and let you back out. The previous
  version spent ~130px of every screen on chrome above the controls.
*/
.toolhead__inner {
  max-width: 1200px;
  margin: 0 auto;
  padding: 9px 24px 10px;
  display: flex;
  align-items: baseline;
  gap: 4px 12px;
  flex-wrap: wrap;
}

.toolhead__crumbs { font-size: 12.5px; color: var(--ink-3); flex: none; }
.toolhead__crumbs a { color: var(--ink-2); text-decoration: none; }
.toolhead__crumbs a:hover { color: var(--signal); }
.toolhead__crumbs span { margin: 0 5px; opacity: 0.55; }

.toolhead__title {
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
  flex: none;
}
.toolhead__lede {
  margin: 0;
  font-size: 12.5px;
  color: var(--ink-3);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The description is the first thing to go when the row gets tight. */
@media (max-width: 720px) { .toolhead__lede { display: none; } }

/* ---------- page picker, shared by the tools that pick pages ---------- */

.pagegrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 16px;
}
.pagecard { display: flex; flex-direction: column; gap: 7px; }

.pagecard__shot {
  position: relative;
  background: #fff;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
  line-height: 0;
}
.pagecard__shot canvas { width: 100%; height: auto; display: block; }

/* A dropped page stays on screen, greyed, so a mis-click is recoverable rather
   than a page silently disappearing from the grid. */
/* The page fades, its button does not. Dimming the whole shot took the undo
   button down with it, leaving a dropped page with no visible way back. */
.pagecard.is-out .pagecard__shot { border-style: dashed; }
.pagecard.is-out .pagecard__shot canvas { opacity: 0.3; filter: grayscale(1); }
.pagecard.is-out .pagecard__shot.is-waiting { opacity: 0.35; }
.pagecard.is-out .pagecard__cap { color: var(--ink-3); text-decoration: line-through; }

.pagecard__act {
  position: absolute;
  top: 6px; right: 6px;
  min-width: 24px; height: 24px;
  padding: 0 7px;
  display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  color: #fff;
  background: var(--signal);
  border: 0;
  border-radius: 100px;
  box-shadow: 0 1px 4px rgba(13, 27, 42, 0.3);
}
.pagecard__act:hover { background: var(--ink); }
.pagecard.is-out .pagecard__act { background: var(--ok); }

.pagecard__cap {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  color: var(--ink-2);
  text-align: center;
}

.pagebar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 18px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--rule-2);
}
.pagebar__count {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-right: auto;
}

/* ---------- tool page footer ---------- */

.toolfoot {
  border-top: 1px solid var(--rule);
  background: var(--card);
  /* No top margin: the tool layout ends flush against it. A gap here showed a
     band of page background between the settings rail and the footer. */
  margin-top: 0;
}
.toolfoot__inner {
  max-width: 1200px;
  margin: 0 auto;
  /* One short row now that the promise paragraph has gone to the landing page,
     so it takes the height of a line of text rather than of a paragraph. */
  padding: 10px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px 20px;
  flex-wrap: wrap;
}


/*
 * .toolfoot__help is retired along with the footer WhatsApp link it styled -
 * see the note in nav.js's promise(). The floating button in whatsapp.js is
 * what every page uses now.
 */
.toolfoot__legal {
  font-size: 12.5px; color: var(--ink-3); text-decoration: none;
  padding: 9px 4px;
}
.toolfoot__legal:hover { color: var(--signal); text-decoration: underline; }

/* The old strip position is retired; the placeholder can stay empty. */
#site-promise:empty { display: none; }

/* several caveats about one file, in one box */
.notice__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.notice__list li { position: relative; padding-left: 14px; line-height: 1.5; }
.notice__list li::before {
  content: "";
  position: absolute;
  left: 0; top: 8px;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.4;
}

.proofnote {
  margin: 0 0 4px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.05em;
  color: var(--ink-3);
}

/* ---------- loading ---------- */

/* A thumbnail that has not been drawn yet: a slow sweep so a waiting grid
   reads as "working" rather than as empty boxes. */
@keyframes shimmer {
  from { background-position: -160% 0; }
  to   { background-position: 260% 0; }
}
/* `.thumb .shot` sets a white ground at two-class specificity, so the waiting
   state has to match it or the sweep is cancelled out and a pending thumbnail
   looks like a finished blank page. */
.is-waiting,
.shot.is-waiting {
  min-height: 40px;         /* holds its space so the grid does not jump */
  /* A solid ground with the sweep passing over it. Putting both stops in the
     gradient let the pale one fill the box and the placeholder read as blank
     white paper rather than as something still loading. */
  background-color: var(--rule-2);
  background-image: linear-gradient(
    100deg,
    transparent 24%,
    var(--shimmer) 42%,
    transparent 60%
  );
  background-size: 220% 100%;
  animation: shimmer 1.5s linear infinite;
}

.spinner {
  display: inline-block;
  width: 13px;
  height: 13px;
  vertical-align: -2px;
  margin-right: 7px;
  border: 2px solid var(--rule);
  border-top-color: var(--signal);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.progress-label.is-busy { color: var(--ink-2); }

@media (prefers-reduced-motion: reduce) {
  .is-waiting,
  .shot.is-waiting { animation: none; background-image: none; }
  .spinner { animation: none; border-top-color: var(--rule); }
}

/* ---------- placeholders while a file is being read ---------- */

.skel {
  height: 12px;
  border-radius: 3px;
}
.skelgroup {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding-bottom: 16px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--rule-2);
}
.skelgroup:last-child { border-bottom: 0; margin-bottom: 0; }
.skelstat {
  display: flex;
  flex-direction: column;
  gap: 8px;
  justify-content: center;
}

/* Reading status, at the top of the stage where the file was dropped. */
.stagestatus {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 0 0 20px;
  font-size: 13px;
  color: var(--ink-2);
}
.stagestatus .progress {
  flex: 1;
  min-width: 80px;
  margin-left: 10px;
}
.stagestatus.hidden { display: none; }

/* ---------- the tool on a phone: stage full screen, settings in a sheet ---------- */

.mobilebar { display: none; }
.sheet, .sheetscrim { display: none; }

/*
 * The `hidden` attribute has to win over the display rules below. A bare class
 * selector outranks the browser's own `[hidden] { display: none }`, so without
 * this the scrim stays laid out - invisible at opacity 0, inset 0, above
 * everything - and silently eats every tap on the page.
 */
.sheet[hidden], .sheetscrim[hidden] { display: none !important; }

@media (max-width: 860px) {
  /*
   * The rail is lifted out of the grid into a bottom sheet, so the stage gets
   * the whole screen. Its desktop height of 100vh with its own scrollbar is
   * what made a phone open the tool on a wall of settings that trapped the
   * scroll.
   */
  .controls {
    height: auto;
    overflow-y: visible;
    position: static;
    border-right: 0;
    border-bottom: 0;
    padding: 4px 0 0;
    background: none;
  }
  .layout { grid-template-columns: 1fr; min-height: 0; }
  .stage { padding: 16px 14px 24px; }

  /* Room for the fixed bar, plus the phone's own home indicator. */
  body.has-mobilebar { padding-bottom: calc(66px + env(safe-area-inset-bottom, 0px)); }
  body.sheet-open { overflow: hidden; }

  .mobilebar {
    display: flex;
    align-items: center;
    gap: 10px;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 70;
    padding: 10px 14px calc(10px + env(safe-area-inset-bottom, 0px));
    background: var(--card);
    border-top: 1px solid var(--rule);
  }
  .mobilebar__settings {
    flex: 1;
    min-height: 46px;
    font-family: var(--mono);
    font-size: 12px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink);
    background: none;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    cursor: pointer;
  }
  .mobilebar__settings[aria-expanded="true"] { border-color: var(--signal); color: var(--signal); }

  /* In the bar, not floating over the preview. */
  .mobilebar .fab {
    position: static;
    flex: 1;
    justify-content: center;
    min-height: 46px;
    padding: 13px 14px;
    box-shadow: none;
    transform: none;
  }
  .mobilebar__settings { flex: 0 0 auto; padding: 0 18px; }

  .sheetscrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 80;
    background: rgba(13, 27, 42, 0.45);
    opacity: 0;
    transition: opacity 0.2s ease;
  }
  .sheetscrim.is-open { opacity: 1; }

  .sheet {
    display: flex;
    flex-direction: column;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 90;
    max-height: 86vh;
    background: var(--card);
    border-top: 1px solid var(--rule);
    border-radius: 14px 14px 0 0;
    box-shadow: 0 -8px 30px rgba(13, 27, 42, 0.22);
    transform: translateY(100%);
    transition: transform 0.22s cubic-bezier(0.32, 0.72, 0, 1);
  }
  .sheet.is-open { transform: translateY(0); }

  .sheet__grab {
    flex: none;
    width: 40px;
    height: 4px;
    margin: 9px auto 3px;
    border-radius: 3px;
    background: var(--rule);
  }
  .sheet__head {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 16px 10px;
    border-bottom: 1px solid var(--rule-2);
    touch-action: none;          /* so the drag-to-dismiss gesture is ours */
  }
  .sheet__title {
    margin: 0;
    font-family: var(--mono);
    font-size: 12px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-2);
  }
  .sheet__body {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 14px 16px calc(20px + env(safe-area-inset-bottom, 0px));
  }
}

@media (prefers-reduced-motion: reduce) {
  .sheet, .sheetscrim { transition: none; }
}

/* ---------- touch targets ---------- */

/*
 * Keyed on the pointer, not the width: a 24px control is too small for a thumb
 * on any size of touch screen.
 */
@media (pointer: coarse) {
  .pagecard__act { min-width: 36px; height: 36px; padding: 0 11px; font-size: 12px; }
  .themetoggle { min-width: 42px; min-height: 42px; }
  .btn--tiny { min-height: 38px; }
  .l-catsbtn, .l-navpanel a { min-height: 44px; }
}

/* ---------- image tools ---------- */

.setting-label { display: block; font-size: 14px; margin-bottom: 5px; }
.setting-hint { margin: 5px 0 0; font-size: 12px; color: var(--ink-3); line-height: 1.45; }
.setting-check {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  padding: 7px 0;
  font-size: 14px;
  cursor: pointer;
}
.setting-check input { margin-top: 2px; flex: none; }

.pagecard__shot img { width: 100%; height: auto; display: block; }
.pagecard.is-out .pagecard__shot img { opacity: 0.3; filter: grayscale(1); }
.pagecard__cap--dim { color: var(--ink-3); }

/* The one crop box, dragged on the first image and used on all of them. */
.cropstage { margin-bottom: 20px; }
.cropwrap {
  position: relative;
  display: inline-block;
  max-width: 100%;
  line-height: 0;
  cursor: crosshair;
  touch-action: none;          /* the drag gesture is ours, not the page's */
  user-select: none;
}
.cropwrap img { max-width: 100%; max-height: 420px; width: auto; display: block; }
.cropdrag {
  position: absolute;
  border: 1px solid var(--signal);
  box-shadow: 0 0 0 9999px rgba(13, 27, 42, 0.45);
  cursor: move;
}

.renamepreview { margin-bottom: 18px; }
.renamepreview__row {
  margin: 0 0 5px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}
.renamepreview__from { color: var(--ink-3); }

/* ---------- GSTIN check ---------- */

.gstin-input {
  width: 100%;
  font-family: var(--mono);
  font-size: 19px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 14px 12px;
}
.gstin-verdict {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  margin-bottom: 18px;
  border: 1px solid var(--rule);
  border-left-width: 3px;
  border-radius: var(--radius);
  font-size: 15px;
}
.gstin-verdict.is-ok { border-left-color: var(--ok); color: var(--ok); }
.gstin-verdict.is-bad { border-left-color: var(--signal); color: var(--signal); }
.gstin-parts { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1px; }
.gstin-part { padding: 12px 14px; background: var(--card); border: 1px solid var(--rule-2); }
.gstin-part b { display: block; font-family: var(--mono); font-size: 15px; margin-bottom: 3px; }
.gstin-part span { font-size: 11.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); }
.gstin-bulk { width: 100%; min-height: 150px; font-family: var(--mono); font-size: 13px; padding: 11px; }
.gstin-row { display: flex; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--rule-2); font-size: 13px; }
.gstin-row code { font-family: var(--mono); flex: none; }
.gstin-row.is-ok code { color: var(--ok); }
.gstin-row.is-bad code { color: var(--signal); }

.toolfoot__by { margin: 0; font-size: 12.5px; color: var(--ink-3); }
.toolfoot__brand { color: var(--ink-2); font-weight: 600; text-decoration: none; }
.toolfoot__brand:hover { color: var(--signal); text-decoration: underline; }

/* ---------- the sign-in gate ---------- */

.gate {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(13, 27, 42, 0.5);
}
.gate__box {
  width: 100%;
  max-width: 380px;
  padding: 26px 24px 22px;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 10px;
  box-shadow: 0 18px 50px rgba(13, 27, 42, 0.28);
}
.gate__title { margin: 0 0 10px; font-size: 19px; }
.gate__text { margin: 0 0 16px; color: var(--ink-2); line-height: 1.55; }
.gate__note {
  margin: -6px 0 16px;
  padding: 9px 11px;
  font-size: 13px;
  color: var(--warn);
  background: var(--paper);
  border-radius: var(--radius);
}
.gate__fine { margin: 14px 0 0; font-size: 12px; color: var(--ink-3); text-align: center; }

/* ---------- the sign-in wall on a tool page ---------- */

/*
 * While we are finding out whether this browser is signed in.
 *
 * visibility, not display: the tools measure elements as they boot, and
 * display:none gives every one of them a zero-size box. This keeps the layout
 * intact and only stops it being seen - which is the whole requirement, since
 * a tool that flashes up and is then replaced reads as a fault.
 *
 * Scoped to <main> so the header stays: on a slow connection a blank page with
 * a masthead is a page that is loading, and a completely blank one is broken.
 */
/* ---- while we work out whether this visitor may be here ----
 *
 * The class is stamped onto <html> by scripts/build.js on every gated page, so
 * this stylesheet - render-blocking, in <head> - applies before the browser
 * draws anything. require-signin.js removes it once it knows.
 *
 * Adding the class from a script at the bottom of <body> was too late: by then
 * the drop zone and the settings rail had already been painted, which is the
 * flash this replaces.
 */
.pc-authcheck main { visibility: hidden; }

/*
 * The tool's furniture lives outside <main>: sheet.js moves the settings rail
 * onto document.body on a narrow screen, download-fab.js adds the floating
 * export button, and the footer carries the help link. Hiding only <main> left
 * an Export button floating over a page that had not decided yet.
 */
.pc-authcheck .fab,
.pc-authcheck .sheet,
.pc-authcheck .sheetscrim,
.pc-authcheck .mobilebar,
.pc-authcheck .toolfoot,
.pc-authcheck body > .controls { visibility: hidden; }

/*
 * A preloader, not an empty page. Nothing is drawn for a moment either way,
 * and the difference between "loading" and "broken" is entirely whether
 * something is there to say so.
 *
 * Built from body's two pseudo-elements so it needs no markup: there is no
 * element to stamp into 22 pages, nothing to remove afterwards, and it cannot
 * be left behind by a script that failed to run.
 */
.pc-authcheck body::before,
.pc-authcheck body::after {
  position: fixed;
  left: 0;
  right: 0;
  text-align: center;
  pointer-events: none;
  z-index: 40;
  /* Late enough not to flicker on a fast connection, where the answer arrives
     before anyone has registered a wait. */
  animation: pc-preload-in 260ms ease-out 220ms both,
             pc-preload-out 0s linear 6s forwards;
}

/* The mark, because it is already the thing on the tab and in the header. */
.pc-authcheck body::before {
  content: "";
  top: 50%;
  margin-top: -46px;
  height: 34px;
  background: center / 34px 34px no-repeat
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='6' y='7' width='3.5' height='18' rx='1.25' fill='%23d62246'/%3E%3Crect x='12.5' y='7' width='7' height='18' rx='1.25' fill='%23d62246'/%3E%3Crect x='23.5' y='7' width='2.5' height='18' rx='1.25' fill='%23d62246'/%3E%3C/svg%3E");
}

.pc-authcheck body::after {
  content: "Checking your account";
  top: 50%;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

@keyframes pc-preload-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pc-preload-out { to { opacity: 0; visibility: hidden; } }

/* The bars read left to right, the way a scanner passes over them. */
@media (prefers-reduced-motion: no-preference) {
  .pc-authcheck body::before { animation:
      pc-preload-in 260ms ease-out 220ms both,
      pc-scan 1100ms ease-in-out 480ms infinite,
      pc-preload-out 0s linear 6s forwards; }
}
@keyframes pc-scan {
  0%, 100% { opacity: 0.45; }
  50%      { opacity: 1; }
}

/*
 * Never leave a page hidden because a script did not arrive.
 *
 * Hiding by default trades a visible flash for a possible blank page: if
 * require-signin.js is blocked by an extension, or a deploy is half-done, the
 * class is never removed and the tool is invisible forever. These animations
 * are the failsafe - they run without JavaScript and reveal the page six
 * seconds in. A working gate has decided long before that, so this only fires
 * when the gate did not run at all.
 *
 * Showing a tool to someone who has not signed in is a business problem. A
 * blank page is a broken product, which is worse, and the server-side check is
 * what should be relied on for the first one regardless.
 */
@keyframes pc-authcheck-failsafe { to { visibility: visible; } }
.pc-authcheck main,
.pc-authcheck .fab,
.pc-authcheck .sheet,
.pc-authcheck .mobilebar,
.pc-authcheck .toolfoot,
.pc-authcheck body > .controls { animation: pc-authcheck-failsafe 0s linear 6s forwards; }

/*
 * With JavaScript off entirely, none of this will ever run. The tools need it
 * anyway, so the honest thing is to show the page and let it say so.
 */
@media (scripting: none) {
  .pc-authcheck main, .pc-authcheck .fab, .pc-authcheck .sheet,
  .pc-authcheck .mobilebar, .pc-authcheck .toolfoot,
  .pc-authcheck body > .controls { visibility: visible; animation: none; }
  .pc-authcheck body::before, .pc-authcheck body::after { content: none; }
}

/* ---- the stage: what went in, and what comes out ----
   The grid on the left is the file; the panel on the right is the result of
   the current settings, composed by the real exporter. Before this, every
   setting below Cropping changed something nobody could see. */
.stagesplit { display: grid; grid-template-columns: 1fr 380px; gap: 22px; align-items: start; }
.stagesplit__title {
  margin: 0 0 10px; font-family: var(--mono); font-size: 10.5px;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3);
}
.stagesplit__out {
  position: sticky; top: 16px;
  background: var(--card); border: 1px solid var(--rule);
  border-radius: var(--radius);
  /* Room at the foot for the floating export button, which is fixed to the
     bottom-right and otherwise sits on top of the last page shown here. */
  padding: 14px 14px 76px;
}
.result__note { margin: 0 0 12px; font-size: 12px; color: var(--ink-3); line-height: 1.5; }
.result__page { margin: 0 0 14px; }
.result__page canvas {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--rule); border-radius: 2px; background: #fff;
}
.result__page figcaption {
  margin-top: 5px; font-family: var(--mono); font-size: 10px;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3);
}

/* On a narrow screen the result comes FIRST: it is the answer to the question
   someone is actually asking while they change a setting. */
@media (max-width: 860px) {
  .stagesplit { grid-template-columns: 1fr; }
  .stagesplit__out { position: static; order: -1; }
}

/* ---------- leading with one job ---------- */

/*
 * The fold-away for the half of a tool you did not come for. Styled as a line
 * of text with a rule above rather than a button, because it is an offer, not
 * the thing the page is for - and the page already has a primary button.
 */
.block--aside { padding-top: 0; }
.toolmode__open {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  padding: 10px 0 0;
  border: 0;
  border-top: 1px solid var(--rule-2);
  background: none;
  color: var(--ink-2);
  cursor: pointer;
}
.toolmode__open b {
  display: block;
  font-size: 13px;
  color: var(--signal);
}
.toolmode__open b::after { content: ' \2192'; }
.toolmode__open span {
  display: block;
  font-size: 11.5px;
  margin-top: 2px;
}
.toolmode__open:hover b { text-decoration: underline; }
.toolmode__open:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }


/* ---------------------------------------------------------------------------
   The WhatsApp button, bottom-right of every page.

   Replaced the Tawk widget, which brought its own iframe, fonts and websocket.
   This is an anchor, a circle and one keyframe, so it costs nothing on the 3G
   phone in a warehouse that the rest of this stylesheet is written for.

   z-index 70 clears everything else here (the highest was 60, the tool rail).
   --------------------------------------------------------------------------- */
/*
 * Support, in the header.
 *
 * It was a circle fixed to the bottom-right corner with a pulsing ring, and
 * what that cost was a corner every page had to steer around: the floating
 * download button was stacked above it to stay reachable, and on the dashboard
 * it still covered a rupee figure, so a seller read "Rs 27,9" where the number
 * was 27,96,000. In the header it is beside the other two header controls,
 * where a person looks for help, and no page has to plan around it.
 *
 * The green is the channel's own, on both grounds, because that glyph is only
 * recognisable in it - it is the one colour on this site that is not ours.
 */
.wa {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 36px;
  padding: 0 11px;
  color: var(--ink-2);
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  text-decoration: none;
  white-space: nowrap;
}
.wa:hover, .wa:focus-visible { color: var(--ink); border-color: #25D366; }
.wa svg { width: 17px; height: 17px; flex: none; color: #25D366; }
.wa__label { font-size: 13px; }

/* The word goes at 1100px, in landing.css with the rest of the header's
   surrenders, so the whole sequence is written down in one place. */
@media (max-width: 1100px) { .wa { padding: 0 9px; } }

/* ---------------------------------------------------------------------------
   Download app
   --------------------------------------------------------------------------- */
.appqr { position: relative; display: inline-flex; }
.l-navpill {
  display: inline-flex;
  align-items: center;
  height: 36px;
  padding: 0 11px;
  font: inherit;
  font-size: 13px;
  color: var(--ink-2);
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  cursor: pointer;
  white-space: nowrap;
}
.l-navpill:hover { color: var(--signal); border-color: var(--signal); }
.appqr__card {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 80;
  width: 208px;
  padding: 13px;
  text-align: center;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: 0 8px 22px rgba(13, 27, 42, 0.14);
}
.appqr__card .appqr__code { display: block; margin: 0 auto 9px; border-radius: 2px; }
.appqr__card b { display: block; font-size: 13px; margin-bottom: 3px; }
.appqr__card p { margin: 0 0 9px; font-size: 12px; color: var(--ink-3); }
.appqr__stores { display: grid; gap: 5px; }
.appqr__stores a {
  padding: 6px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-2);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  text-decoration: none;
}
.appqr__stores a:hover { color: var(--signal); border-color: var(--signal); }
.appqr__tail {
  display: block;
  margin-top: 8px;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--ink-3);
}

/* Never on paper. */
@media print { .wa, .appqr { display: none; } }

/* ---------------------------------------------------------------------------
   The signed-in rail

   Two widths, one component. Open on the dashboard and the account screens;
   52px of icons everywhere else, because every tool page already has a left
   column and that column is the tool. The navigation gives way to the work and
   keeps only enough of itself to get somewhere else.

   It wraps <main> in a flex row from script, so no page's own grid is touched
   and nothing in thirty-three files has to know the rail exists.
   --------------------------------------------------------------------------- */
.pc-shell { display: flex; align-items: stretch; min-height: 0; }
.pc-shell > main { flex: 1; min-width: 0; }

.pc-rail {
  flex: none;
  /* 216 and not 196: the fold-outs put real tool names in here, and at 196
     "Custom packing label" and "Packing labels from a CSV" both ended in an
     ellipsis. Still narrow enough that the widest of them clips - the title
     attribute carries the full name - but most now read whole. */
  width: 216px;
  display: flex;
  flex-direction: column;
  background: var(--card);
  border-right: 1px solid var(--rule);
  /* The header is sticky above it; the rail sticks under the header and holds
     its own scroll, so a long tool page does not scroll the menu away. */
  position: sticky;
  top: 0;
  align-self: flex-start;
  /* Exactly the viewport, so the border runs the whole way down rather than
     stopping where the links happen to end and leaving the page showing
     through below it. */
  height: 100vh;
  /* Visible, not auto: the collapse tab sits half outside this box and a
     scrolling box clips whatever leaves it. .pc-rail__scroll takes the
     scroll instead. `position: sticky` is also what makes this the tab's
     containing block. */
  overflow: visible;
}

.pc-rail__scroll { gap: 2px; padding: 10px 0 12px; }

.pc-rail__top { display: flex; align-items: center; padding: 0 10px 4px; }
/*
  The collapse tab, straddling the rail's right border.

  Half in and half out, which is the whole design: the only thing an edge
  handle can do is move that edge, so the position explains the control and no
  label is needed. Two earlier versions sat in the brand bar and neither was
  understood - a doubled chevron, then a drawing of a sidebar that was a smudge
  at the size it rendered.

  A direct child of .pc-rail and NOT of the scrolling wrapper, because a
  scrolling box clips whatever leaves it and this deliberately leaves it.
*/
.pc-rail__shrink {
  position: absolute;
  /* Level with the brand mark - 10px of wrapper padding plus half an 18px
     brand row, less half this 22px tab. A sidebar handle is looked for beside
     the logo, and there it is also clear of the first menu row. */
  top: 8px;
  /*
   * Inside the border, not straddling it.
   *
   * Half outside looked right on the dashboard and overlapped the tool pages:
   * a tool's settings column starts at the rail's right edge, so the
   * protruding half of the tab sat on top of it. Reserving a gutter for it
   * would have shifted every tool page sideways to make room for a button.
   * Flush against the edge keeps the "this handle moves this edge" reading
   * and costs nobody a pixel.
   */
  right: 3px;
  z-index: 65;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 50%;
  color: var(--ink-3);
  background: var(--card);
  border: 1px solid var(--rule);
  cursor: pointer;
  /* Lifted off the border so it reads as sitting on top of it rather than
     being a notch cut out of it. */
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.14);
}
.pc-rail__shrink:hover { color: var(--signal); border-color: var(--signal); }
.pc-rail__shrink .pc-rail__ico { width: 13px; height: 13px; opacity: 1; }

/*
 * At 52px the brand and the toggle will not sit side by side - 36px of usable
 * width between two 17px glyphs leaves nothing. They stack instead, which
 * keeps both: the mark is still the way home and the toggle is still the only
 * way back to the open rail.
 */
/*
 * The mark goes at 52px, and the tab has the row to itself.
 *
 * They collided: the tab straddles the right border and the centred mark sits
 * six pixels from it, so a 52px rail drew a logo and a button on top of each
 * other. Nothing is lost - Dashboard is the first icon below and is where a
 * signed-in seller actually means when they reach for a logo.
 */
.pc-rail--icons .pc-rail__brand { display: none; }
.pc-rail--icons .pc-rail__top { justify-content: center; min-height: 22px; padding: 0 0 4px; }

.pc-rail__biz { padding: 2px 12px 10px; border-bottom: 1px solid var(--rule-2); }
.pc-rail__biz b {
  display: block;
  font-size: 13px;
  line-height: 1.3;
  /* A business name can be 160 characters; two lines of it and then stop. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.pc-rail__biz span {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--ink-3);
}

.pc-rail__label {
  padding: 12px 12px 4px;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.pc-rail__group { display: grid; gap: 1px; padding: 0 7px; }

.pc-rail__row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 8px;
  border-radius: var(--radius);
  font-size: 13.5px;
  color: var(--ink-2);
  text-decoration: none;
  white-space: nowrap;
}
.pc-rail__row:hover { background: var(--rule-2); color: var(--ink); }
.pc-rail__row.is-on { background: var(--rule-2); color: var(--signal); font-weight: 600; }
.pc-rail__ico { width: 16px; height: 16px; flex: none; opacity: 0.8; }
.pc-rail__row.is-on .pc-rail__ico { opacity: 1; }
.pc-rail__dot { width: 16px; height: 16px; flex: none; border: 1.5px solid currentColor; border-radius: 3px; opacity: 0.6; }

/* ---- a category, and the tools that fold out of it ---- */
/*
  The rail is the only tools menu a signed-in seller has - the header's five
  dropdowns are taken off the moment it mounts - so a category has to reach a
  tool and not just the page that lists them.

  Open/closed is a class on the wrapper rather than a height animation:
  the list is between four and nine rows and nobody is waiting on it, and a
  transition on height needs a measured pixel value that goes wrong the first
  time a tool is added.
*/
.pc-rail__head {
  width: 100%;
  font: inherit;
  font-size: 13.5px;
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
}
.pc-rail__caret {
  margin-left: auto;
  font-size: 15px;
  line-height: 1;
  opacity: 0.55;
  transition: transform 0.12s ease;
}
.pc-rail__cat.is-open > .pc-rail__head { color: var(--ink); }
/* The category the current page lives in. At 52px this is the ONLY thing
   saying which tool is open, because there is no fold-out and no tool row. */
.pc-rail__head.is-here { color: var(--signal); font-weight: 600; }
.pc-rail__head.is-here .pc-rail__ico { opacity: 1; }
.pc-rail--icons .pc-rail__head.is-here { background: var(--rule-2); }
.pc-rail__cat.is-open .pc-rail__caret { transform: rotate(90deg); }

.pc-rail__sub { display: none; padding: 1px 0 5px; }
.pc-rail__cat.is-open .pc-rail__sub { display: grid; gap: 1px; }
/* The heading belongs to the flyout only; at 216px the row above it is the
   heading and says the same word twice. */
.pc-rail__subh { display: none; }

/*
 * Indented to the width of the icon above plus its gap, so the tools line up
 * under the category's NAME rather than under its glyph - which is what makes
 * them read as inside it without a rule or a box around them.
 */
.pc-rail__tool {
  display: block;
  padding: 5px 8px 5px 33px;
  border-radius: var(--radius);
  font-size: 12.5px;
  color: var(--ink-2);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pc-rail__tool:hover { background: var(--rule-2); color: var(--ink); }
.pc-rail__tool.is-on { color: var(--signal); font-weight: 600; }
/* Listed, not linked. Leaving it out would make the rail disagree with the
   directory, which does show it. */
.pc-rail__tool.is-soon { color: var(--ink-3); cursor: default; }
.pc-rail__tool.is-soon small {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-left: 6px;
}
.pc-rail__all { color: var(--ink-3); font-style: italic; }

/* ---- the brand, at the head of the rail ---- */
.pc-rail__brand {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
  color: var(--ink);
  text-decoration: none;
}
.pc-rail__mark { display: flex; flex: none; color: var(--signal); }
.pc-rail__mark svg { width: 18px; height: 18px; }
.pc-rail__word {
  font-family: var(--mono);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.06em;
  white-space: nowrap;
}

/*
 * "Hide", beside the chevron.
 *
 * The word is the part that works: two glyphs were tried here and each was
 * something a seller had to be told the meaning of once. It goes at 52px,
 * where there is no room for it and where anybody looking at the rail has
 * already pressed this control to get there.
 */


/* ---- who is signed in, at the foot ---- */
/*
  The rail is a frame, and the box inside it is what scrolls.

  That split exists for one reason: the collapse tab sits ON the rail's right
  border, half outside it, and a box that scrolls on one axis clips the other.
  A scrolling rail cut the tab in half. So the rail holds only the tab and the
  wrapper; the wrapper holds everything else and takes the scrollbar.
*/
.pc-rail__scroll {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overflow-x: hidden;
}

/*
  Every scrollbar inside the signed-in app.
  
  The rail was themed first and the tool pages were not, which left a 16px
  platform scrollbar down the settings column and a 15px one down the page -
  both of them light grey on a dark theme, which is what "the scroll looks
  ugly" was actually about. The rule is scoped to .pc-railed so the marketing
  site keeps the plain platform bar a visitor expects.
*/
.pc-railed,
.pc-railed .controls,
.pc-railed .stage {
  scrollbar-width: thin;
  scrollbar-color: var(--rule) transparent;
}
.pc-railed ::-webkit-scrollbar,
.pc-railed::-webkit-scrollbar { width: 9px; height: 9px; }
.pc-railed ::-webkit-scrollbar-track,
.pc-railed::-webkit-scrollbar-track { background: transparent; }
.pc-railed ::-webkit-scrollbar-thumb,
.pc-railed::-webkit-scrollbar-thumb {
  background: var(--rule);
  border-radius: 5px;
  /* Inset by a transparent border so the thumb reads as floating in the
     gutter rather than filling it edge to edge. */
  border: 2px solid transparent;
  background-clip: content-box;
}
.pc-railed ::-webkit-scrollbar-thumb:hover,
.pc-railed::-webkit-scrollbar-thumb:hover { background-color: var(--ink-3); background-clip: content-box; }

/*
  The rail's own, which is the one that also auto-hides: thin, themed, and
  out of sight until it is wanted.

  A fold-out category can push the rail past the viewport, so it has to scroll -
  but the platform's default bar is a 15px light-grey channel welded to the
  right edge of a 216px menu, and in dark mode it stays light grey. It read as
  a seam between the rail and the page rather than as a control.

  Two mechanisms because no single one covers the browsers we have: the
  standard `scrollbar-*` properties (Firefox, and Chrome 121+) and the WebKit
  pseudo-elements (every Safari, and Chrome before that). They are allowed to
  disagree about a pixel; both are a thin thumb in the rule colour on no track.

  Transparent until the pointer is in the rail, so a rail that merely CAN
  scroll does not look like one that is scrolled. `scrollbar-gutter: stable`
  keeps the 6px reserved either way - without it every row shifts sideways on
  hover, which is far worse than a visible bar.
*/
.pc-rail__scroll {
  scrollbar-width: thin;
  scrollbar-color: transparent transparent;
  scrollbar-gutter: stable;
}
.pc-rail:hover .pc-rail__scroll,
.pc-rail:focus-within .pc-rail__scroll { scrollbar-color: var(--rule) transparent; }

.pc-rail__scroll::-webkit-scrollbar { width: 6px; }
.pc-rail__scroll::-webkit-scrollbar-track { background: transparent; }
.pc-rail__scroll::-webkit-scrollbar-thumb {
  background: transparent;
  border-radius: 3px;
}
.pc-rail:hover .pc-rail__scroll::-webkit-scrollbar-thumb,
.pc-rail:focus-within .pc-rail__scroll::-webkit-scrollbar-thumb { background: var(--rule); }
.pc-rail__scroll::-webkit-scrollbar-thumb:hover { background: var(--ink-3); }

.pc-rail__foot {
  margin-top: auto;
  padding: 9px 12px;
  border-top: 1px solid var(--rule-2);
  display: grid;
  gap: 7px;
}
.pc-rail__who { display: flex; align-items: center; gap: 8px; min-width: 0; }
.pc-rail__av {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  flex: none;
  background: var(--rule-2);
  color: var(--ink-2);
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: 9px;
}
.pc-rail__whoin { min-width: 0; }
.pc-rail__whoin b {
  display: block;
  font-size: 11.5px;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* An email is longer than this rail and a mobile is not, so it clips. The
   whole of it is on the account screen, one tap away in the row below. */
.pc-rail__whoin span {
  display: block;
  font-family: var(--mono);
  font-size: 9px;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pc-rail__links { display: flex; gap: 12px; font-size: 11px; }
.pc-rail__links a,
.pc-rail__links button {
  font: inherit;
  color: var(--ink-2);
  text-decoration: none;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.pc-rail__links a:hover,
.pc-rail__links button:hover { color: var(--ink); }
.pc-rail__links a.is-on { color: var(--signal); }

/* At 52px there is no room for a name, an email or two links - the avatar is
   the whole foot, and the account screen is one of the icons above it. */
.pc-rail--icons .pc-rail__whoin,
.pc-rail--icons .pc-rail__links,
.pc-rail--icons .pc-rail__word { display: none; }
.pc-rail--icons .pc-rail__foot { padding: 9px 0; justify-items: center; }
.pc-rail--icons .pc-rail__brand { justify-content: center; }
.pc-rail__plan {
  padding: 7px 15px 0;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--ok);
}
.pc-rail__plan.is-soon { color: var(--signal); }

/* ---- the application's own topbar ---- */
/*
  A signed-in page is not the website.

  The masthead sells the product: brand, five tool menus, a Log In button. A
  seller who has paid for this does not need any of that - they know what it
  is, the tools are a column away in the rail, and they are already in. So on
  a railed page the same header element becomes a slim bar carrying the name
  of the SCREEN and the three controls that are genuinely global: the app
  popup, support, and the theme picker.

  Done by taking pieces off nav.js's header rather than rendering a second
  one, because two headers is two headers to keep right - and the three
  controls mount themselves into slots that header writes.
*/
.pc-railed .l-nav { position: static; }
.pc-railed .l-nav__inner {
  max-width: none;
  padding: 7px 16px;
  gap: 10px;
}
.pc-railed .l-brand,
.pc-railed .l-navauth,
.pc-railed .l-drawerlogin,
.pc-railed .l-dashtab,
.pc-railed .l-dashslot { display: none; }

/*
 * An empty spacer, which is all that is left of the crumb.
 *
 * It named the screen for a while. The tool pages draw their own breadcrumb
 * trail inside the page, so it was the second one on screen - and the rail
 * marks the category you are in, which answers the same question with no
 * furniture at all. The element stays because dressHeader() uses it as the
 * guard that stops the three controls being mounted twice.
 */
.l-crumb { flex: 1; min-width: 0; }

/*
  The header's tools menu, removed where the rail is.

  Not deleted from nav.js: the same header is rendered for a visitor who is
  not signed in, on a landing page or the home page, and there is no rail
  there - that menu is the only way into the tools and the only internal
  linking a crawler follows. So it goes away exactly when its replacement
  appears, which is what `pc-railed` on <html> means.

  The burger goes with it. Left behind it would open an empty drawer, since
  the drawer IS this menu at a narrow width.
*/
.pc-railed .l-navmenu,
.pc-railed .l-navburger { display: none; }

/* ---- the icon width ---- */
.pc-rail--icons .pc-rail {
  width: 52px;
  padding-left: 0;
  padding-right: 0;
}
.pc-rail--icons .pc-rail__name,
.pc-rail--icons .pc-rail__biz,
.pc-rail--icons .pc-rail__label,
.pc-rail--icons .pc-rail__plan { display: none; }
.pc-rail--icons .pc-rail__group { padding: 0 8px; }
/*
  ---- the flyout ----

  At 52px the same fold-out opens BESIDE the rail instead of inside it. Five
  icons that all went to the same directory page was an icon rail nobody could
  use; this is the shape every application with a collapsed sidebar uses, and
  it costs no markup - the panel is the one `category()` already built.

  Positioned against the row, not the rail, so it opens level with the icon
  that was pressed. The rail needs `overflow: visible` for it to escape, which
  is why the scroll moves to an inner wrapper... except it cannot, so instead
  the flyout is `position: fixed`-like within the rail's own stacking context
  and the rail stops scrolling when a flyout is open. See the rule below.
*/
.pc-rail--icons .pc-rail__caret { display: none; }
.pc-rail--icons .pc-rail__cat { position: relative; }

.pc-rail--icons .pc-rail__cat.is-open .pc-rail__sub {
  position: absolute;
  left: calc(100% + 6px);
  top: -6px;
  z-index: 70;
  min-width: 206px;
  padding: 7px;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.22);
}
.pc-rail--icons .pc-rail__subh {
  display: block;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 2px 8px 6px;
}
/* The tools are the whole panel here, so they lose the indent that made them
   read as nested under a category name at 216px. */
.pc-rail--icons .pc-rail__tool { padding-left: 8px; }

/*
 * A flyout escapes the rail, and a scrolling box clips whatever leaves it.
 * With one open the rail stops scrolling for as long as it is open - there is
 * nothing to scroll to anyway, because the panel beside it is what is being
 * read.
 */
.pc-rail--icons .pc-rail:has(.pc-rail__cat.is-open) { overflow: visible; }

/* The icon of an open category stays lit, so it is obvious which of the five
   the panel belongs to. */
.pc-rail--icons .pc-rail__cat.is-open > .pc-rail__head {
  background: var(--rule-2);
  color: var(--signal);
}
.pc-rail--icons .pc-rail__row { justify-content: center; padding: 9px 0; }
.pc-rail--icons .pc-rail__top { justify-content: center; padding: 0 0 4px; }

/*
 * On a tool page the rail cannot be opened out at all - there is no width for
 * two left columns - so the control that would do it is not offered.
 */
/*
  A tool page's rail used to hide its own toggle, which left the seller with
  five icons and no way to see what any of them were. It opens now - over the
  page rather than pushing it, so the tool's own column does not reflow when
  somebody goes looking for the menu.
*/
/*
  Closed, it is an ordinary 52px column in the flex row and the tool starts
  beside it - which is what it has always been.

  OPENED, it leaves the flow and lies over the page, because a tool page's
  working column is the one being used and widening the menu from 52px to
  216px would reflow the seller's work mid-task. The shell keeps the 52px it
  had, so nothing moves at all: the extra 164px is what overlaps.
*/
.pc-rail--over:not(.pc-rail--icons) .pc-shell { padding-left: 52px; }
.pc-rail--over:not(.pc-rail--icons) .pc-rail {
  position: fixed;
  left: 0;
  z-index: 60;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.22);
}

/*
 * Below the drawer breakpoint the rail becomes a strip across the top: a 52px
 * column on a 390px phone is 13% of the screen spent on navigation that the
 * header's own menu already carries.
 */
@media (max-width: 1200px) {
  .pc-shell { display: block; }
  .pc-rail {
    width: auto !important;
    height: auto;
    flex-direction: row;
    align-items: center;
    gap: 4px;
    padding: 6px 8px;
    border-right: 0;
    border-bottom: 1px solid var(--rule);
    position: static;
    overflow-x: auto;
  }
  .pc-rail__top, .pc-rail__biz, .pc-rail__label, .pc-rail__plan { display: none; }
  .pc-rail__foot { margin-top: 0; padding-top: 0; border-top: 0; }
  .pc-rail__group { display: flex; gap: 4px; padding: 0; }
  .pc-rail__row { padding: 7px 9px; }
  .pc-rail__name { display: none; }
}

/* Paper gets the page, not the furniture. */
@media print { .pc-rail { display: none; } }
