/*
  styles.css — the whole look of the tool. Nothing in here changes behaviour.

  Class names are load bearing. app.js toggles .open on .sect.fold, .compact
  and .away on #msel, and sets body className to "touch|mouse tab-<name>".
  EMPTY in app.js toggles .bare on #scaleSect and props in properties.js
  toggles it on #propsSect. Rename any of those here and the accordion, the
  mobile sheets, the tab bar or a rail section stop working with nothing
  reporting it.

  .bare is display only. It takes a rail section off the screen while it has
  nothing to say. FOLD never sees it, so the section keeps whatever open or
  shut state it was saved with and comes back exactly as it was left.

  #empty is the first run card and it is positioned as a percentage of
  #sheetWrap, matching the plan area of the sheet, 24,202 to 1090,1099 of
  1587x1123. Move the plan area in sheet.js and those four numbers go stale
  with nothing reporting it. It is pointer-events:none with the card itself
  pointer-events:auto, so an armed symbol can still be placed around it. On
  mobile the sheet pans on a viewBox, so those percentages mean nothing there
  and the media query resets it to the whole wrapper.

  Added to a phone home screen the tool runs with no browser chrome, so the
  insets are real. Anything fixed to a screen edge inside the mobile media
  query pads itself with env(safe-area-inset-*), or the status bar at the top
  or the home bar at the bottom sits over it.

  Anything sitting at the bottom of the screen on a phone is position:fixed,
  never absolute inside #desk. #desk is 100vh tall and a browser's address bar
  puts its bottom edge below the fold, so an absolute bottom:0 in there is off
  screen on the one layout it matters on. #fab, .msheet and #pages are all
  fixed for that reason.

  --pagebar on body in the mobile block is the height of the design page bar.
  Four rules read it: #desk gives up that much height, #pages takes it, and
  #fab and .msheet sit above it. They stack drawing, sheet, page bar, tab bar
  with nothing overlapping. Change the height there and all four follow.

  #tally is a flex column and #tallyList is the only part of it that scrolls,
  so the total and the copy button stay on the bottom edge on a long job.
  #tallyList carries min-height:0 or it refuses to shrink and shoves the footer
  off the screen. The mobile block turns the panel off and on again by display,
  so the rule that turns it back on hands back flex, never block.

  Three rules that look wrong and are not:
  - .sect.fold>.sectbody is display:none, never height:0. The body stays in the
    DOM while shut so every control keeps its id and its handler.
  - .sect.fold.open>.secthead .stat is display:none. A shut header shows its
    section's status line, an open one does not, because the real line is
    sitting right under it.
  - .hint:empty hides itself. #revNote is a .hint that is blank most of the
    time and a hint is a box now, so without that rule it prints an empty box.

  Never put min-width:0 on .row .btn. A flex item defaults to min-width:auto,
  which is what stops a button shrinking narrower than its own label. The room
  naming box in rooms.js puts thirteen name buttons in one .row, and with
  min-width:0 they all squash to an even width and the words spill out over the
  top of each other.

  A shut section header wraps: the name and the chevron on the first row, the
  status line on a row of its own under them. .stat is flex 1 1 100% and the
  chevron is order 2, so do not take either off without checking a long status
  on a phone. That is what put "Walls, rooms and elevations" down the page one
  word at a time.

  Two controls are shown by input type, not by screen size: #liftWrap is touch
  only and #altHint is mouse only. Both hang off the touch or mouse class that
  app.js keeps on <body>, so neither is in a media query and neither is set
  from js. A narrow window on a laptop is still a mouse.

  A .sect.fold.pin is a pinned section, always open and with no header click.
  It drops the open tint and the orange bar so the two pinned sections at the
  top of the rail read as one block rather than two open accordion sections.
  #palette is the only thing in there that can grow, so it carries its own
  max-height and its own scroll. That cap is desktop only: on mobile the
  palette moves into #msheetBody, which is already a scroller, and two nested
  scrollers fight each other.

  Padding lives on .secthead and .sectbody, not on .sect.fold, so the header
  hover band and the open tint run the full width of the rail. The mobile block
  near the bottom sets both again, so change them in pairs.

  A bare select is width:100%, set around line 227. One dropped into a flex row
  takes the whole row and pushes whatever sits beside it off the edge, so give
  it width:auto there. The business card's rows are where this keeps biting.

  Colour var NAMES are load bearing and unchanged: --orange, --muted and --line
  are spelled out in js files. Add a var, do not rename one. The values are the
  studio skin and every one of them moved, warm charcoal to cool slate. A rule
  that still carries a raw hex is either paper (#fff, the sheet, the tutorial
  art backing) or a one off that has no var yet.

  Numbers are mono and tabular, prose is not. --mono plus tabular-nums goes on
  anything that counts or measures: the status line, tally counts, the total,
  category counts, the legend counts and .num inputs. A tabular figure is a
  fixed width, so a count ticking 9 to 10 does not shove the row about. Never
  put it on a .stat or a .hint, those hold sentences.

  #desk carries the coordinate dot grid as a background-image, so it is chrome
  and never reaches a print. Nothing inside svg#sheet knows about it. It is set
  as background-color plus background-image, not the background shorthand, or
  the image is wiped by the next rule that sets it.

  Anything floating over the drawing uses --glass with a backdrop blur, not an
  opaque panel: #deskbar, #selbar, the first run card, and the mobile deskbar
  buttons and status pill. -webkit-backdrop-filter rides with every one of them
  for iOS, which is the only place the tool runs off a home screen.

  Any rule that sets display has to spell out [hidden] as well, or the attribute
  stops hiding. .cropout, .linkbtn, .btn, .acctrow and .gfield each carry their
  own. PHOTOS.outUI, buildTally and AUTH all hide with the attribute, so drop
  the rule and an empty Outside plan crop fold, a dead Copy everything link or a
  sign up field that belongs to the other form sits on screen.

  html.gated hides the tool behind the sign in wall with visibility, never
  display. fit in app.js measures desk.clientWidth during boot, which happens
  behind the gate, and display:none gives it nought, so the sheet comes up
  sized for nothing on the first frame after signing in.
*/

  :root{
    --chrome:#0E131D; --panel:#141B28; --panel-2:#1B2434; --line:#232D42;
    --text:#E8EDF7; --muted:#94A3B8; --orange:#F97316; --warn:#EF4444;
    /* added with the restyle, nothing outside this file reads them */
    --line-2:#35425E; --edge:#2A3448; --hint:#111827; --ink:#0B0F17;
    --open:#18212F; --hover:#1E2839;
    /* the studio skin. Every one of these was a hex sitting in a rule before. */
    --orange-2:#FB923C;          /* orange, hovered */
    --on:rgba(249,115,22,.15);   /* the tint under an armed or active control */
    --field:#0A1017;             /* inside a text box, darker than the panel */
    --sunk:#0F1725;              /* a block set into a panel, list bodies */
    --scroll:#2E3A52; --scroll-2:#3E4C6B;
    --bad:#FCA5A5; --bad-line:#5B2733; --bad-fill:#2A151B;
    --amber:#F59E0B;             /* a count that is short, not wrong */
    --cyan:#06B6D4;              /* measurement and snap readouts */
    --glass:rgba(17,23,36,.88);  /* anything floating over the drawing */
    --mono:ui-monospace,"JetBrains Mono","SFMono-Regular","Cascadia Mono",Menlo,Consolas,monospace;
    /* Cursors the sheet draws itself. The Windows arrow and crosshair are XOR
       cursors: the system inverts them against the pixels underneath, and on a
       composited page that inversion arrives a frame or more late, so the cursor
       sits white on white paper until something repaints. These are painted
       shapes, dark on a white halo, and never wait on that. */
    --cur-arrow:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='20'%20height='22'%20viewBox='0%200%2020%2022'%3E%3Cpath%20d='M2%201.5L2%2017.5L6%2013.8L8.6%2019.4L11.2%2018.2L8.7%2012.8L13.2%2012.8Z'%20fill='%23111111'%20stroke='%23ffffff'%20stroke-width='1.6'%20stroke-linejoin='round'/%3E%3C/svg%3E") 2 2, default;
    --cur-cross:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%3E%3Cg%20fill='none'%20stroke-linecap='round'%3E%3Cg%20stroke='%23ffffff'%20stroke-width='3.4'%3E%3Cpath%20d='M12%201.5V9'/%3E%3Cpath%20d='M12%2015V22.5'/%3E%3Cpath%20d='M1.5%2012H9'/%3E%3Cpath%20d='M15%2012H22.5'/%3E%3C/g%3E%3Cg%20stroke='%23111111'%20stroke-width='1.4'%3E%3Cpath%20d='M12%201.5V9'/%3E%3Cpath%20d='M12%2015V22.5'/%3E%3Cpath%20d='M1.5%2012H9'/%3E%3Cpath%20d='M15%2012H22.5'/%3E%3C/g%3E%3C/g%3E%3Ccircle%20cx='12'%20cy='12'%20r='1.1'%20fill='%23111111'%20stroke='%23ffffff'%20stroke-width='0.9'/%3E%3C/svg%3E") 12 12, crosshair;
  }
  *{box-sizing:border-box}
  html,body{height:100%;margin:0;touch-action:manipulation}
  /* Four zones. The bar spans the top, then rail, drawing and tally side by
     side under it. Every other child of body is fixed or display:none on a
     mouse, so nothing else lands in a cell. Add a flow level element to the
     page and it will, so give it a grid-area or keep it fixed. */
  body{background:var(--chrome);color:var(--text);--top:52px;--supbar:34px;
    font:14px/1.45 ui-sans-serif,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
    display:grid;grid-template-columns:auto 1fr auto;grid-template-rows:var(--top) 1fr;
    overflow:hidden;-webkit-user-select:none;user-select:none;
    -webkit-text-size-adjust:100%}
  input,textarea,select{-webkit-user-select:text;user-select:text}

  aside{grid-row:2;height:100%;min-height:0;overflow-y:auto;background:var(--panel);
    -webkit-overflow-scrolling:touch;
    scrollbar-width:thin;scrollbar-color:var(--scroll) transparent}
  aside::-webkit-scrollbar{width:10px}
  aside::-webkit-scrollbar-track{background:transparent}
  aside::-webkit-scrollbar-thumb{background:var(--scroll);border-radius:6px;border:3px solid var(--panel)}
  aside::-webkit-scrollbar-thumb:hover{background:var(--scroll-2)}

  /* ---------- the application bar, Zone A ---------- */
  /* #brand and #deskbar are borrowed. Both are authored inside the bar and
     syncMode in app.js hands them back to #rail and #desk on a phone, where
     the bar is display:none. Everything the mobile HUD sets on #deskbar is
     unset again under #topbar, or the two fight over the same element. */
  /* Support access. Fixed across the very top so it cannot be scrolled away or
     covered, and body gives up the same height so nothing sits under it. The
     inset is real on a phone with the tool added to the home screen. */
  #supportBar{position:fixed;top:0;left:0;right:0;z-index:60;display:flex;
    align-items:center;gap:10px;min-height:var(--supbar);padding:0 12px;
    padding-top:env(safe-area-inset-top,0px);
    background:var(--bad-fill);border-bottom:1px solid var(--bad-line);
    color:var(--bad);font-size:12.5px}
  #supportBar[hidden]{display:none}
  #supportBar b{letter-spacing:.3px;text-transform:uppercase;font-size:11px}
  #supportBar em{font-style:normal;color:var(--text);font-weight:600}
  #supportBar #supportLeft{margin-left:auto;color:var(--amber);white-space:nowrap}
  #supportBar .btn{padding:3px 9px;font-size:12px}
  body.supporting{padding-top:calc(var(--supbar) + env(safe-area-inset-top,0px))}

  #topbar{grid-area:1/1/2/4;display:flex;align-items:center;gap:14px;min-width:0;
    padding-right:14px;background:var(--panel);border-bottom:1px solid var(--line);z-index:20}
  #topBrand{flex:0 0 322px;width:322px;align-self:stretch;display:flex;align-items:center;
    border-right:1px solid var(--line)}
  #topBrand #brand{flex:1;min-width:0;position:static;border-bottom:0;padding:0 16px}
  #topJob{min-width:0;display:flex;flex-direction:column;gap:1px}
  #jobCrumb{font-size:12.5px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #jobSub{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:10.5px;
    letter-spacing:-.01em;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #topbar #deskbar{margin-left:auto;flex:1 1 auto;min-width:0;justify-content:flex-end}
  #topbar #deskbar .btn{flex:0 0 auto}
  /* the live line reads left of the controls, so it is order -1 and not the
     last child it is in the DOM. It grows into whatever the job crumb and the
     buttons leave rather than stopping at a fixed width, so a long error reads
     as a sentence instead of three words and an ellipsis. */
  #topbar #deskbar .status{order:-1;flex:1 1 0;min-width:90px;margin:0 8px 0 0;
    font-size:12.5px;
    text-align:right;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
    background:var(--chrome);border:1px solid var(--line);border-radius:20px;padding:5px 11px}
  #topExport{flex:0 0 auto}

  #rail{grid-column:1;width:322px;border-right:1px solid var(--line)}
  #tally{grid-column:3;width:276px;border-left:1px solid var(--line)}

  #brand{display:flex;align-items:center;gap:11px;padding:14px 16px;
    border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--panel);z-index:6}
  #brand .mark{width:34px;height:34px;flex:0 0 34px;border-radius:8px;overflow:hidden;
    display:grid;place-items:center;background:#fff}
  #brand .mark img{width:100%;height:100%;object-fit:contain;display:block}
  #brand b{font-size:15px;font-weight:700}
  #brand span{display:block;font-size:11px;color:var(--muted);font-weight:400;margin-top:1px}

  .sect{padding:14px 16px;border-bottom:1px solid var(--line)}
  .sect h2{margin:0 0 10px;font-size:13px;font-weight:700;color:var(--text)}

  /* collapsible rail sections. The body stays in the DOM while shut, so every
     control keeps its id and every existing handler keeps working. */
  .sect.fold{padding:0}
  .secthead{width:100%;display:flex;align-items:center;flex-wrap:wrap;gap:10px;row-gap:2px;
    background:none;border:0;color:var(--text);font:700 13.5px/1.3 inherit;padding:13px 16px;
    margin:0;cursor:pointer;text-align:left}
  .sect.fold.open{background:var(--open);box-shadow:inset 2px 0 0 var(--orange)}
  .secthead:hover{background:var(--hover)}
  .secthead:focus-visible{outline:2px solid var(--orange);outline-offset:-2px}
  /* the status line gets its own row under the name. .lbl grows and .stat used
     to sit beside it on a flex basis of auto, so a long status squeezed the
     name down to one word a line and the two ran into each other. The order
     numbers are what keep the chevron up on the first row. */
  .secthead .lbl{order:1;flex:1 1 auto;min-width:0}
  .sect.fold>.secthead .chev{order:2}
  .secthead .stat{order:3;flex:1 1 100%;min-width:0;font-style:normal;font-weight:500;
    font-size:11px;line-height:1.4;color:var(--muted);white-space:nowrap;overflow:hidden;
    text-overflow:ellipsis}
  .sect.fold.open>.secthead .stat{display:none}
  .secthead .chev{flex:0 0 10px;font-style:normal;font-size:14px;line-height:1;color:var(--muted);
    transition:transform .15s ease}
  .sect.fold.open>.secthead .chev{transform:rotate(90deg);color:var(--orange)}
  .sect.fold>.sectbody{display:none}
  .sect.fold.open>.sectbody{display:block;padding:2px 16px 16px}

  /* the pinned zone at the top of the rail. Always open, no header click, see
     FOLD.pin in app.js */
  #railTop .sect.fold.pin,#railTop .sect.fold.pin.open{background:none;box-shadow:none}
  .sect.fold.pin>.secthead{cursor:default;padding-bottom:9px}
  .sect.fold.pin>.secthead:hover{background:none}
  .sect.fold.pin.open>.sectbody{padding-top:0}
  #palette{max-height:min(40vh,340px);overflow-y:auto;overscroll-behavior:contain;
    margin-right:-7px;padding-right:7px;scrollbar-width:thin;scrollbar-color:var(--scroll) transparent}
  #palette::-webkit-scrollbar{width:8px}
  #palette::-webkit-scrollbar-track{background:transparent}
  #palette::-webkit-scrollbar-thumb{background:var(--scroll);border-radius:5px;border:2px solid var(--panel)}

  /* shown by what you are driving it with, not by how wide the window is.
     app.js keeps touch or mouse on <body> through every className rewrite. */
  body.mouse #liftWrap{display:none}
  body.touch #altHint{display:none}

  /* the strip that starts each run of accordion sections */
  .grouphead{margin:0;padding:13px 16px 9px;font:700 10.5px/1.3 inherit;color:var(--muted);
    text-transform:uppercase;letter-spacing:.09em;background:var(--chrome);
    border-bottom:1px solid var(--line)}

  /* a divided block inside a section, for the bits that used to be their own */
  .subsect{margin-top:15px;border-top:1px solid var(--line);padding-top:13px}
  .subsect h3{margin:0 0 10px;font:700 10.5px/1.3 inherit;color:var(--muted);
    text-transform:uppercase;letter-spacing:.09em}

  .btn{appearance:none;border:1px solid var(--line);background:var(--panel-2);color:var(--text);
    border-radius:8px;padding:9px 12px;font:500 13px/1.2 inherit;cursor:pointer;
    min-height:36px;display:inline-flex;align-items:center;justify-content:center;gap:6px}
  /* inline-flex above beats the hidden attribute on its own. Without this a
     button with hidden set still shows. */
  .btn[hidden]{display:none}
  .btn:hover{border-color:var(--line-2);background:#232E40}
  .btn:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
  .btn[disabled]{opacity:.38;cursor:default}
  .btn.primary{background:var(--orange);border-color:var(--orange);color:#0B0F17;font-weight:700}
  .btn.primary:hover{background:var(--orange-2);border-color:var(--orange-2)}
  .btn.wide{width:100%}
  .btn.danger{color:var(--bad);border-color:var(--bad-line);background:var(--bad-fill)}
  .btn.danger:hover{color:#FECDD3;border-color:#7A3441;background:#36191F}
  .btn.on{border-color:var(--orange);background:var(--on);color:var(--text)}
  .btn.mini{padding:6px 10px;font-size:12px;border-radius:7px;min-height:31px}
  .btn.tiny{padding:4px 8px;font-size:11.5px;border-radius:6px;min-height:0}
  .row{display:flex;gap:8px}
  .row .btn{flex:1}

  /* the search holds the top of the symbols section while the list scrolls
     under it. #symWrap is the desktop home; on a phone the whole lot moves
     into #msheetBody, which is already a scroller, so the sticky is harmless
     there and the rule needs no media query. */
  #symSearch{margin-bottom:10px;position:sticky;top:0;z-index:2}
  .cat{margin-bottom:6px}
  .cathead{width:100%;display:flex;align-items:center;gap:7px;background:none;border:0;
    color:var(--muted);font:700 10.5px/1 inherit;text-transform:uppercase;letter-spacing:.08em;
    padding:9px 2px;cursor:pointer;text-align:left}
  .cathead:hover{color:var(--text)}
  .cathead .cc{margin-left:auto;font-family:var(--mono);font-variant-numeric:tabular-nums;font-weight:600;opacity:.7;text-transform:none;letter-spacing:0}
  .fam{display:flex;margin-bottom:5px}
  .famMain{flex:1;min-width:0;display:flex;align-items:center;gap:9px;background:var(--panel-2);
    border:1px solid var(--line);border-right:0;border-radius:8px 0 0 8px;padding:6px 9px;cursor:pointer;
    color:var(--text);font-family:inherit;text-align:left}
  .famMain b{font-size:12.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .famMain svg{flex:0 0 30px}
  .famChev{flex:0 0 30px;background:var(--panel-2);border:1px solid var(--line);border-radius:0 8px 8px 0;
    color:var(--muted);cursor:pointer;font-size:10px;font-family:inherit}
  .famMain:hover,.famChev:hover{background:#232E40;border-color:var(--line-2)}
  .fam.on .famMain,.fam.on .famChev{border-color:var(--orange);background:var(--on)}
  .vars{margin:0 0 8px 11px;border-left:2px solid var(--edge);padding-left:8px}
  .var{width:100%;display:flex;align-items:center;gap:8px;background:none;border:0;color:var(--muted);
    font:400 12px/1.3 inherit;padding:6px 5px;cursor:pointer;text-align:left;border-radius:6px}
  .var:hover{background:var(--panel-2);color:var(--text)}
  .var.sel{color:var(--orange);font-weight:600}
  .var svg{flex:0 0 26px}

  label.f{display:block;margin-bottom:11px}
  label.f span{display:block;font:600 11px/1.3 inherit;color:var(--muted);margin-bottom:5px;
    letter-spacing:.02em}
  input[type=text],input[type=number],input[type=password],input[type=email],textarea,select{width:100%;background:var(--field);border:1px solid var(--line);
    color:var(--text);border-radius:7px;padding:8px 10px;font:13px/1.4 inherit;font-family:inherit}
  input::placeholder,textarea::placeholder{color:#64748B}
  input:hover,textarea:hover,select:hover{border-color:var(--line-2)}
  input:focus,textarea:focus,select:focus{outline:none;border-color:var(--orange);
    box-shadow:0 0 0 2px rgba(249,115,22,.22)}
  textarea{resize:vertical;min-height:118px}
  input[type=range]{flex:1;min-width:0;accent-color:var(--orange)}
  input[type=checkbox]{accent-color:var(--orange);width:16px;height:16px;flex:0 0 16px}
  input[type=color]{width:36px;height:30px;padding:0;border:1px solid var(--line);background:none;border-radius:7px;cursor:pointer}
  .num{width:72px;flex:0 0 72px;text-align:right;padding:7px 8px;font-size:12.5px;font-family:var(--mono);font-variant-numeric:tabular-nums;}

  /* an explanation, or a status line. Boxed so it reads as a note and not as
     another control. Empty ones hide themselves, see the header. */
  .hint{font-size:11.5px;line-height:1.5;color:var(--muted);margin:11px 0 0;
    padding:9px 11px;background:var(--hint);border-radius:7px;border-left:2px solid var(--edge)}
  .hint:empty{display:none}
  #scaleState,#geoState,#roomState{border-left-color:var(--orange)}
  /* The Outside plan crop fold, #phOut. A native details, so
     shut is one line and there is no handler to lose. The [hidden] rule has
     to stay: anything setting display on .cropout would beat the attribute
     and leave an empty fold on screen. */
  .cropout{margin:10px 0 0;border:1px solid var(--line);border-radius:7px;background:var(--panel-2)}
  .cropout[hidden]{display:none}
  .cropout>summary{display:flex;align-items:center;gap:8px;padding:8px 11px;cursor:pointer;list-style:none;
    font-size:11.5px;font-weight:600;color:var(--text)}
  .cropout>summary::-webkit-details-marker{display:none}
  .cropout>summary::before{content:"";flex:0 0 7px;height:7px;border-radius:50%;background:var(--orange)}
  .cropout>summary .chev{margin-left:auto;font-style:normal;font-size:14px;line-height:1;color:var(--muted);
    transition:transform .15s ease}
  .cropout[open]>summary .chev{transform:rotate(90deg);color:var(--orange)}
  .cropout>div{padding:0 11px 11px}
  .corow{display:flex;gap:8px;justify-content:space-between;font-size:12px;padding:6px 0;border-top:1px solid var(--line)}
  .corow i{font-style:normal;font-family:var(--mono);font-variant-numeric:tabular-nums;color:var(--muted);white-space:nowrap}
  .cropout .hint{margin-top:8px}
  /* the quiet second copy under Copy the list */
  .linkbtn{display:block;margin:8px auto 0;background:none;border:0;padding:4px;color:var(--muted);
    font:inherit;font-size:11.5px;text-decoration:underline;text-underline-offset:2px;cursor:pointer}
  .linkbtn[hidden]{display:none}
  .linkbtn:hover{color:var(--text)}
  .tit .tout{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:11px;color:var(--muted);white-space:nowrap}
  .kbd{background:var(--field);border:1px solid var(--line);border-radius:4px;padding:1px 5px;font-size:11px}
  .check{display:flex;align-items:flex-start;gap:9px;font-size:12.5px;line-height:1.4;
    margin:0 -8px 1px;padding:7px 8px;border-radius:7px;cursor:pointer}
  .check:hover{background:var(--panel-2)}
  .check input{margin-top:1px}
  .check+.pair{margin-top:11px}
  .pair{display:flex;gap:9px;align-items:center;margin-bottom:10px}
  .pair>span{font-size:11.5px;color:var(--muted);width:58px;flex:0 0 58px}
  #props .none{font-size:12.5px;color:var(--muted);margin:0;padding:10px 11px;
    background:var(--hint);border-radius:7px;border-left:2px solid var(--edge)}
  .cols{display:flex;gap:6px;align-items:center;margin-bottom:11px;flex-wrap:wrap}
  .cdot{width:26px;height:26px;border-radius:7px;border:2px solid transparent;cursor:pointer}
  .cdot[aria-pressed="true"]{border-color:var(--text)}

  #tally{display:flex;flex-direction:column;overflow:hidden}
  #tally h2{flex:0 0 auto;display:flex;align-items:center;gap:8px;
    background:var(--panel);margin:0;padding:15px 14px 12px;
    font-size:13px;font-weight:700;color:var(--text);border-bottom:1px solid var(--line)}
  #tallyCount{margin-left:auto;font-style:normal;font-family:var(--mono);
    font-variant-numeric:tabular-nums;font-size:11px;font-weight:700;color:var(--orange);
    background:var(--on);border:1px solid rgba(249,115,22,.3);border-radius:20px;padding:2px 9px}
  #alerts{flex:0 0 auto;padding:0;max-height:38%;overflow-y:auto}
  #tallyList{flex:1 1 auto;min-height:0;overflow-y:auto}
  .alert{background:var(--bad-fill);border-bottom:1px solid var(--bad-line);padding:11px 13px;
    box-shadow:inset 2px 0 0 var(--warn)}
  .alert b{display:block;font-size:12.4px;font-weight:700;color:var(--bad);margin-bottom:3px}
  .alert p{margin:0 0 8px;font-size:11.5px;line-height:1.5;color:#E3BCC1}
  .tgroup{border-bottom:1px solid var(--line)}
  .trow{display:flex;gap:9px;align-items:flex-start;padding:10px 12px;cursor:pointer}
  .trow:hover{background:var(--hover)}
  .trow .g{flex:0 0 32px;height:26px;display:grid;place-items:center}
  .trow .n{flex:1;min-width:0}
  .trow .n b{display:block;font-size:12.3px;font-weight:600}
  .trow .n i{display:block;font-style:normal;font-size:11px;color:var(--muted);margin-top:2px}
  .trow .c{flex:0 0 auto;font-family:var(--mono);font-variant-numeric:tabular-nums;
    font-size:11.5px;font-weight:700;color:var(--orange);
    background:var(--on);border:1px solid rgba(249,115,22,.3);border-radius:20px;padding:2px 8px}
  .trow .chev{flex:0 0 11px;color:var(--muted);font-size:10px;padding-top:3px}
  .trow .acts{display:flex;gap:4px;margin-top:7px;flex-wrap:wrap}
  .titems{padding:2px 12px 10px;background:var(--sunk)}
  .tit{display:flex;gap:5px;align-items:center;margin-bottom:5px;flex-wrap:wrap}
  .tit .ix{flex:0 0 16px;font-size:11px;color:var(--muted);text-align:right}
  .tit input[type=text]{flex:1;min-width:70px;padding:5px 8px;font-size:12px}
  .tit.on input[type=text]{border-color:var(--orange)}
  .wirebox{flex:0 0 100%;display:flex;align-items:center;gap:7px;font-size:11.5px;color:var(--muted);
    padding:5px 0 2px 21px}
  .trow.empty{color:var(--muted);font-size:12.5px;display:block;padding:22px 16px;
    cursor:default;text-align:center;line-height:1.6}
  #tallyFoot{flex:0 0 auto;padding:12px 12px 16px;
    border-top:1px solid var(--line);background:var(--chrome)}
  #total{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:11.5px;color:var(--muted);margin:0 0 10px}

  #desk{grid-row:2;grid-column:2;min-width:0;min-height:0;height:100%;
    overflow:auto;padding:20px;-webkit-overflow-scrolling:touch;
    background-color:var(--ink);
    background-image:radial-gradient(rgba(148,163,184,.14) 1px,transparent 1px);
    background-size:22px 22px}
  #deskbar{display:flex;align-items:center;gap:6px;min-width:0}
  #deskbar .status{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:11.5px;letter-spacing:-.01em;
    color:var(--muted);margin-left:auto;text-align:right;flex:1 1 140px;
    position:relative;overflow:hidden}
  /* Indeterminate on purpose. The sketch call reports no progress, so a
     percentage would be invented. This says working and the seconds in the
     text say how long. sayBusy in js/state.js is the only thing that sets it. */
  #deskbar .status.busy::after{content:"";position:absolute;left:0;bottom:0;
    width:38%;height:3px;background:var(--orange);
    animation:statsweep 1.15s ease-in-out infinite}
  @keyframes statsweep{0%{transform:translateX(-100%)}100%{transform:translateX(265%)}}
  #sheetWrap{position:relative;margin:0 auto;width:max-content}
  /* First run card over the blank sheet. Deliberately NOT inside svg#sheet:
     cleanSvg only empties #ui and #guide, so anything in the sheet svg prints.
     The box is the plan area in sheet units, 24,202 to 1090,1099 of 1587x1123.
     pointer-events:none on the wrapper so an armed symbol can still be placed
     around the card. Only the card itself takes clicks. There is no scrim: the
     sheet behind it is blank, buildFrame in sheet.js no longer draws help text
     on an empty sheet. */
  #empty{position:absolute;left:1.5%;top:18%;width:67.2%;height:79.9%;z-index:3;
    display:flex;align-items:center;justify-content:center;padding:16px;
    pointer-events:none}
  #empty[hidden]{display:none}
  /* Actions next to the selected symbol, mouse only. Outside svg#sheet for the
     same reason #empty is: cleanSvg keeps everything else in there. Positioned
     in sheet pixels times zoom, so it stays put through a zoom. */
  #selbar{position:absolute;z-index:4;display:flex;gap:6px;padding:5px;white-space:nowrap;
    background:var(--glass);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
    border:1px solid var(--line-2);border-radius:9px;box-shadow:0 8px 32px -4px rgba(0,0,0,.6)}
  #selbar[hidden]{display:none}
  #empty .ecard{pointer-events:auto;max-width:330px;text-align:center;
    background:var(--glass);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
    border:1px solid var(--line-2);border-radius:12px;
    padding:18px 18px 15px;box-shadow:0 8px 32px -4px rgba(0,0,0,.6)}
  #empty .ecard b{display:block;font-size:15px;margin:0 0 5px}
  #empty .ecard p{margin:0 0 13px;font-size:12.5px;color:var(--muted);line-height:1.5}
  #empty .erow{display:flex;flex-direction:column;gap:8px}
  #empty .ehint{margin:13px 0 0;font-size:11.5px}
  /* Design pages. A column under the sheet on a mouse, so the add button sits
     under the last page and moves down as pages are added. Written by PAGES.ui
     in js/pages.js. Outside svg#sheet for the same reason #empty is. */
  #pages{display:flex;flex-direction:column;align-items:flex-start;gap:7px;
    margin:16px 0 6px;max-width:100%}
  #pageList{display:flex;flex-direction:column;gap:6px;min-width:190px}
  .prow{display:flex;align-items:stretch;gap:6px}
  .prow .pname{flex:1;text-align:left;justify-content:flex-start;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .prow.on .pname{border-color:var(--orange);color:var(--text);font-weight:700}
  .prow .pdel{flex:0 0 auto;padding-left:10px;padding-right:10px;color:var(--muted)}
  .prow .pdel:hover{color:var(--bad);border-color:#7A3441}
  /* a page duplicated off another. Dashed, so a copy reads as a second view of
     a page already in the job rather than another page of work. */
  .prow.copy .pname{border-style:dashed}
  /* A rail section with nothing to say yet. Covers #propsSect in #railTop and
     #scaleSect in the accordion. FOLD never sees this, it is display only. */
  #rail .sect.bare{display:none}
  svg#sheet{display:block;box-shadow:0 25px 60px -15px rgba(0,0,0,.8),0 0 0 1px rgba(255,255,255,.08);background:#fff;
    touch-action:none;-webkit-user-select:none;user-select:none}
  svg#sheet *{-webkit-user-select:none;user-select:none}
  /* --cur-arrow and --cur-cross are in :root, with the reason. */
  svg#sheet{cursor:var(--cur-arrow)}
  svg#sheet.armed{cursor:var(--cur-cross)}
  .item{cursor:move}
  .dimh{cursor:grab}
  .dimh:active{cursor:grabbing}
  svg#sheet.armed .item{cursor:move}
  svg#sheet.armed.force,svg#sheet.armed.force .item{cursor:var(--cur-cross)}
  svg#sheet.wiring,svg#sheet.wiring .item{cursor:pointer}

  #tut{position:fixed;inset:0;background:rgba(10,9,8,.9);z-index:70;display:flex;
    align-items:center;justify-content:center;padding:20px}
  #tut[hidden]{display:none}
  #tutCard{background:var(--panel);border:1px solid var(--line);border-radius:14px;
    width:min(760px,100%);max-height:92vh;display:flex;flex-direction:column;overflow:hidden;
    box-shadow:0 30px 80px rgba(0,0,0,.65)}
  #tutTop{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--line);flex:0 0 auto}
  #tutTop b{flex:1;font-size:15px;font-weight:700}
  #tutStep{font-size:12px;color:var(--muted)}
  #tutArt{background:#EDF1F7;padding:14px;flex:0 0 auto}
  #tutArt svg{display:block;width:100%;height:auto;max-height:34vh}
  #tutBody{padding:16px;overflow-y:auto;flex:1 1 auto;-webkit-overflow-scrolling:touch}
  #tutBody h3{margin:0 0 10px;font-size:15px;font-weight:700}
  #tutBody ul{margin:0;padding-left:19px}
  #tutBody li{margin-bottom:9px;font-size:13.5px;line-height:1.55}
  #tutBody li b{font-weight:700}
  #tutFoot{display:flex;align-items:center;gap:10px;padding:12px 16px;border-top:1px solid var(--line);flex:0 0 auto}
  #tutDots{flex:1;display:flex;gap:5px;justify-content:center;flex-wrap:wrap}
  #tutDots i{width:7px;height:7px;border-radius:50%;background:var(--line-2);cursor:pointer}
  #tutDots i.on{background:var(--orange)}
  #tutAgain{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--muted);
    padding:0 16px 12px;cursor:pointer}
  @media (max-width:1100px){
    #tut{padding:0}
    #tutCard{width:100%;height:100%;max-height:none;border-radius:0;border:0}
    #tutArt svg{max-height:26vh}
    #tutBody li{font-size:14px}
  }
  #modal,#setPanel{position:fixed;inset:0;background:rgba(12,10,9,.72);display:grid;place-items:center;z-index:60;padding:20px}
  #modal[hidden],#setPanel[hidden]{display:none}
  #modal .card,#setPanel .card{background:var(--panel);border:1px solid var(--line);border-radius:12px;
    width:min(560px,100%);max-height:88vh;overflow:auto;box-shadow:0 30px 70px rgba(0,0,0,.6)}
  .mhead{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--line);
    position:sticky;top:0;background:var(--panel);z-index:2}
  .mhead b{flex:1;font-size:15px;font-weight:700}
  .mbody{padding:16px}
  .seth{margin:0 0 10px;font:700 10.5px/1.3 inherit;color:var(--muted);
    text-transform:uppercase;letter-spacing:.08em}
  .swatches{display:flex;gap:7px;margin-bottom:12px}
  .sw{width:34px;height:30px;border-radius:7px;border:2px solid transparent;cursor:pointer}
  .sw[aria-pressed="true"]{border-color:var(--text)}
  .shapes{display:grid;grid-template-columns:repeat(5,1fr);gap:6px;margin-bottom:12px}
  .sh{background:var(--panel-2);border:1px solid var(--line);border-radius:7px;padding:6px 2px;cursor:pointer}
  .sh[aria-pressed="true"]{border-color:var(--orange);background:var(--on)}
  .sh small{display:block;font-size:9.5px;color:var(--muted);margin-top:1px}
  #b_art{background:#fff;border-radius:8px;padding:8px;display:grid;place-items:center;margin-bottom:10px;min-height:56px}
  #preview{background:#fff;border-radius:9px;padding:10px;display:grid;place-items:center;margin-bottom:14px}
  .clist .ci{display:flex;gap:8px;align-items:center;padding:9px 0;border-bottom:1px solid var(--line)}
  .clist .ci .pv{flex:0 0 44px;background:#fff;border-radius:6px;display:grid;place-items:center;padding:4px}
  .clist .ci b{flex:1;font-size:13px;font-weight:600}
  .miss{margin:0 0 10px;padding-left:18px;font-size:13px}
  .miss li{margin-bottom:4px;color:var(--bad)}

  /* ---------- mobile ---------- */
  #tabbar{display:none}
  #fab,.msheet,#armchip,#mpad{display:none}

  @media (max-width:1100px){
    /* How tall the design page bar under the drawing is. #desk gives up this
       much height, the bar takes it and #fab clears it. Change it here only. */
    body{display:block;overflow:hidden;--pagebar:46px;--top:0px}
    /* the bar's job is done by #deskbar over the drawing and the tab bar below
       it. syncMode moves #brand and #deskbar out of here before it is hidden. */
    #topbar{display:none}
    /* Added to the home screen the app runs with no browser chrome, so the
       status bar sits over the top of these two. */
    #rail,#tally{position:fixed;left:0;right:0;top:0;bottom:calc(60px + env(safe-area-inset-bottom));
      width:auto;height:auto;z-index:30;display:none;border:0;padding-bottom:20px;
      padding-top:env(safe-area-inset-top)}
    body.tab-tools #rail{display:block}
    /* flex, not block. #tally is a column with its own inner scroller and the
       shared rule above just turned it off, so turning it back on has to hand
       the column back with it. */
    body.tab-items #tally{display:flex}
    /* the footer carries its own bottom padding now, so the 20px the shared
       rule above puts on the panel would sit under it as a dead strip */
    #tally{padding-bottom:0}
    #tallyFoot{padding-bottom:calc(16px + env(safe-area-inset-bottom))}

    #desk{position:relative;padding:0;overflow:hidden;width:100%;
      height:calc(100vh - 60px - var(--pagebar) - env(safe-area-inset-bottom))}
    #sheetWrap{width:100%;height:100%;margin:0}
    #empty{left:0;top:0;width:100%;height:100%;background:none}
    /* #msel does this job on a phone. Belt and braces, SELBAR.upd bails on MOB. */
    #selbar{display:none}
    /* A bar of its own between the drawing and the tab bar, not a column under
       the sheet. Fixed, not absolute: #desk is 100vh tall and a phone's address
       bar puts its bottom edge below the fold, which is why #fab and the bottom
       sheets are fixed too. #desk gives up --pagebar so the bar never covers the
       drawing. The bottom sheets still come over it while one is open. */
    #pages{position:fixed;left:0;right:0;z-index:8;margin:0;
      bottom:calc(60px + env(safe-area-inset-bottom));height:var(--pagebar);
      flex-direction:row;align-items:center;gap:6px;padding:0 10px;
      background:var(--panel);border-top:1px solid var(--line)}
    /* the pages scroll sideways, the add button stays put on the end */
    #pageList{flex:1 1 auto;flex-direction:row;min-width:0;gap:6px;
      overflow-x:auto;-webkit-overflow-scrolling:touch}
    #pages .btn.mini{border-radius:9px;padding:7px 11px;white-space:nowrap}
    /* the shadow is the edge the pages scroll under, so a cut off page reads
       as more to come rather than a clipped button. It goes on the left hand
       one of the two, which is the one the list actually runs behind. */
    #pages #pageAdd,#pages #pageDupe{flex:0 0 auto}
    #pages #pageDupe{box-shadow:-10px 0 10px -7px rgba(0,0,0,.6)}
    /* tight pairs so a delete reads as belonging to the page on its left */
    #pageList .prow{gap:2px}
    #pages .prow .pdel{padding-left:9px;padding-right:9px}
    svg#sheet{width:100%;height:100%;box-shadow:none}

    #deskbar{position:absolute;top:calc(8px + env(safe-area-inset-top));left:8px;right:8px;
      margin:0;padding:0;background:none;border:0;gap:6px;flex-wrap:wrap;align-items:flex-start;z-index:8}
    #deskbar .btn.mini{background:var(--glass);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
      border-color:var(--line-2);border-radius:9px;padding:9px 11px;
      box-shadow:0 3px 10px rgba(0,0,0,.35)}
    #deskbar .status{order:9;flex:0 0 100%;margin:6px auto 0;text-align:center;color:var(--text);
      background:var(--glass);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
      border:1px solid var(--line);border-radius:20px;padding:8px 14px;font-size:12.5px;max-width:94%;
      box-shadow:0 3px 10px rgba(0,0,0,.35);transition:opacity .35s}
    #deskbar .status.hide{opacity:0}

    #tabbar{display:flex;position:fixed;left:0;right:0;bottom:0;height:calc(60px + env(safe-area-inset-bottom));
      z-index:45;background:var(--panel);border-top:1px solid var(--line);padding-bottom:env(safe-area-inset-bottom)}
    #tabbar button{flex:1;background:none;border:0;color:var(--muted);font:700 12px/1.3 inherit;
      display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;cursor:pointer}
    #tabbar button .d{width:6px;height:6px;border-radius:50%;background:transparent}
    #tabbar button[aria-pressed="true"]{color:var(--orange)}
    #tabbar button[aria-pressed="true"] .d{background:var(--orange)}

    #fab{display:grid;place-items:center;position:fixed;right:14px;
      bottom:calc(76px + var(--pagebar) + env(safe-area-inset-bottom));width:58px;height:58px;border-radius:29px;
      background:var(--orange);color:#0B0F17;border:0;font:400 32px/1 inherit;
      box-shadow:0 8px 22px rgba(0,0,0,.5);z-index:38;cursor:pointer}
    body.tab-tools #fab,body.tab-items #fab{display:none}

    /* clear of the design page bar, so the page you are on never goes behind a
       sheet while you are working */
    .msheet{display:block;position:fixed;left:0;right:0;
      bottom:calc(60px + var(--pagebar) + env(safe-area-inset-bottom));
      z-index:39;background:var(--panel);border-top:1px solid var(--line);border-radius:16px 16px 0 0;
      box-shadow:0 -14px 34px rgba(0,0,0,.5);padding:6px 14px 18px;overflow-y:auto;
      -webkit-overflow-scrolling:touch}
    #msheet{max-height:62vh}
    #msel{max-height:46vh;transition:transform .16s ease}
    #msel.away{transform:translateY(112%)}
    #msel.compact{max-height:none;overflow:visible}
    #msel.compact #mselBody{display:none}
    .msheet[hidden]{display:none}
    body.tab-tools .msheet,body.tab-items .msheet{display:none}
    .grab{width:44px;height:5px;border-radius:3px;background:var(--line-2);margin:2px auto 9px;cursor:pointer}
    .mhead2{display:flex;align-items:center;gap:8px;margin-bottom:10px}
    .mhead2 b{flex:1;font-size:14px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
    /* wraps and stretches, so the shut row of three and the open row of five
       both fill the width without a hole on the end */
    .mquick{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px}
    .mquick .btn{flex:1 1 26%;padding:9px 4px;font-size:12.5px;white-space:nowrap;
      overflow:hidden;text-overflow:ellipsis}
    /* the fold control in the selected sheet header. Shut it reads Options with
       the chevron lying on its side, open it reads Less and points down, same
       way round as the rail sections. */
    .mfold{display:flex;align-items:center;gap:6px}
    .mfold .chev{font-style:normal;font-size:13px;line-height:1;color:var(--muted);
      transition:transform .15s ease;transform:rotate(90deg)}
    #msel.compact .mfold .chev{transform:rotate(0deg)}
    #mpad{height:58px;border:1px dashed var(--line-2);border-radius:10px;background:
      repeating-linear-gradient(45deg,#18202F,#18202F 6px,#131B29 6px,#131B29 12px);
      display:grid;place-items:center;margin-bottom:10px;touch-action:none;cursor:grab}
    #mpad span{font-size:11.5px;color:var(--muted);pointer-events:none}
    #mpad.on{border-color:var(--orange);background:var(--on)}
    #mpad.on span{color:var(--text)}
    #mpad[hidden]{display:none}
    .mquick .btn[disabled]{opacity:.35}

    #armchip{display:flex;align-items:center;gap:9px;position:fixed;left:50%;transform:translateX(-50%);
      top:calc(58px + env(safe-area-inset-top));z-index:37;background:var(--on);border:1px solid var(--orange);
      border-radius:20px;padding:6px 7px 6px 14px;font-size:12.5px;color:var(--text);
      box-shadow:0 4px 14px rgba(0,0,0,.4);max-width:88vw}
    #armchip[hidden]{display:none}
    body.tab-tools #armchip,body.tab-items #armchip{display:none}
    #armchip span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

    .btn{padding:11px 13px;font-size:14px;min-height:44px}
    .btn.mini{padding:9px 11px;font-size:13px;min-height:38px}
    .btn.tiny{padding:7px 10px;font-size:12.5px;min-height:0}
    .famMain{padding:10px 9px}
    .famChev{flex:0 0 44px;font-size:12px}
    .var{padding:11px 6px;font-size:13.5px}
    .trow{padding:13px 12px}
    .cathead{padding:13px 2px;font-size:11.5px}
    input[type=text],input[type=number],textarea,select{font-size:16px;padding:10px 11px}
    .num{width:84px;flex:0 0 84px}
    input[type=range]{height:32px}
    input[type=checkbox]{width:22px;height:22px;flex:0 0 22px}
    .check{font-size:13.5px;padding:10px 8px;margin-bottom:2px}
    .sect{padding:16px}
    .cdot{width:32px;height:32px}
    .sect.fold{padding:0}
    .secthead{padding:15px 16px;font-size:14.5px}
    /* everything in #railTop lives in a bottom sheet here, so the whole pinned
       zone goes and the Setup tab is settings only. syncMode moves all four of
       its controls out, see the app.js header. */
    #palette{max-height:none;overflow:visible;margin-right:0;padding-right:0}
    #railTop{display:none}
    #msheetBody #symBtns{margin-top:12px}
    .grouphead{padding:14px 16px 10px;font-size:11px}
    .secthead .chev{flex:0 0 12px;font-size:15px}
    .sect.fold.open>.sectbody{padding:2px 16px 18px}
    .hint{font-size:12.5px;padding:10px 12px}
    .cropout>summary{font-size:12.5px;padding:11px 12px}
    .corow{font-size:13px}
    .linkbtn{font-size:12.5px;padding:8px}
    #modal,#setPanel{padding:12px}
    #modal .card,#setPanel .card{max-height:84vh}
  }
  #elev{position:fixed;inset:0;background:rgba(24,21,19,.72);display:grid;place-items:center;z-index:60;padding:18px}
  #elev[hidden]{display:none}
  #elevCard{background:var(--panel);border:1px solid var(--line);border-radius:14px;
    width:min(1180px,100%);max-height:94vh;display:flex;flex-direction:column;overflow:hidden}
  #elevTop{display:flex;align-items:center;gap:10px;padding:12px 14px;border-bottom:1px solid var(--line)}
  #elevTop b{font-size:14px;font-weight:700}
  #elevStep{margin-left:auto;font-size:12px;color:var(--muted)}
  #elevArt{padding:12px;overflow:hidden;background:var(--ink);flex:1;position:relative;touch-action:none}
  #elevArt svg{display:block;width:100%;height:auto;background:#fff;border-radius:6px;
    transform-origin:0 0;will-change:transform}
  #elevHint{position:absolute;right:14px;bottom:10px;font-size:11px;color:#6B7B95;pointer-events:none}
  #elevFoot{display:flex;align-items:center;gap:10px;padding:10px 14px;border-top:1px solid var(--line)}
  #elevDots{display:flex;gap:6px;margin:0 auto}
  #elevDots i{width:7px;height:7px;border-radius:50%;background:var(--line-2);cursor:pointer}
  #elevDots i.on{background:var(--orange)}
  #elevEmpty{color:var(--muted);font-size:13px;padding:26px;text-align:center}

  /* ------------------------------------------------ photo markup editor */
  /* Same card shape as #elev on purpose. #pmkArt is touch-action:none: one
     finger draws in there and two fingers pan, so the browser must not claim
     either gesture first. */
  #pmk{position:fixed;inset:0;background:rgba(24,21,19,.82);display:grid;place-items:center;z-index:62;padding:18px}
  #pmk[hidden]{display:none}
  /* The card is given a real height on purpose. #pmkArt is flex:1 and the svg
     inside it has no intrinsic height, so a card sized to its content gives the
     picture nought and the whole editor comes out as a sliver with the toolbar
     over the top. min-height:0 on the art is what lets it shrink inside the
     column instead of pushing the footer off. */
  #pmkCard{background:var(--panel);border:1px solid var(--line);border-radius:14px;
    width:min(1180px,100%);height:100%;max-height:100%;display:flex;flex-direction:column;
    overflow:hidden;position:relative}
  #pmkTop{display:flex;align-items:center;gap:8px;padding:12px 14px;border-bottom:1px solid var(--line)}
  #pmkTop b{font-size:14px;font-weight:700;margin-right:auto}
  #pmkArt{padding:12px;overflow:hidden;background:var(--ink);
    flex:1 1 auto;min-height:0;position:relative;display:flex;touch-action:none}
  /* The svg fills the art box as a flex child and the picture is letterboxed
     inside it by preserveAspectRatio. The view is the viewBox, set in
     photo-markup.js. Never put a transform back on this, and never take it out
     of the flow: absolutely positioned it stops giving the art box any height
     and the card collapses. */
  #pmkArt svg{flex:1 1 auto;width:100%;height:100%;min-width:0;min-height:0;
    background:#000;border-radius:6px}
  #pmkArt.grab{cursor:grabbing}
  #pmkHint{position:absolute;right:14px;bottom:10px;font-size:11px;color:#6B7B95;pointer-events:none}
  #pmkFoot{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
    flex:0 0 auto;padding:10px 14px;border-top:1px solid var(--line)}
  #pmkKinds{display:flex;gap:5px;flex-wrap:wrap}
  #pmkKinds .btn.on{background:var(--orange);border-color:var(--orange);color:#0B0F17}
  #pmkSymBtn.on{background:var(--orange);border-color:var(--orange);color:#0B0F17}
  /* both panels sit over the picture. The picker uses the rail palette's own
     classes, so it reads the same as the symbol list on the sheet. */
  .pmkpanel{position:absolute;left:0;right:0;bottom:0;max-height:62%;z-index:2;
    background:var(--panel);border-top:1px solid var(--line);
    display:flex;flex-direction:column;overflow:hidden}
  .pmkpanel[hidden]{display:none}
  .pmkpanelTop{display:flex;gap:8px;align-items:center;
    padding:10px 12px;border-bottom:1px solid var(--line)}
  .pmkpanelTop input{flex:1;min-width:0}
  .pmkpanelTop b{flex:1;font-size:12.5px;font-weight:700}
  .pmkpanelBody{overflow-y:auto;overscroll-behavior:contain;padding:10px 12px 14px}
  .legrow{width:100%;display:flex;align-items:center;gap:9px;background:none;border:0;
    color:var(--text);text-align:left;padding:5px 6px;border-radius:7px;cursor:pointer}
  .legrow:hover{background:var(--panel-2)}
  .legrow .g{flex:0 0 28px;display:grid;place-items:center}
  .legrow .n{flex:1;min-width:0;font-size:12.5px;overflow:hidden;
    text-overflow:ellipsis;white-space:nowrap}
  .legrow .n i{display:block;font-style:normal;font-size:10.5px;color:var(--muted)}
  .legrow .c{flex:0 0 auto;font-size:11.5px;font-weight:700;font-family:var(--mono);font-variant-numeric:tabular-nums;}
  .legrow .c.ok{color:var(--muted)}
  .legrow .c.under{color:var(--amber)}
  .legrow .c.over{color:var(--warn)}
  #pmkCount{font-size:11.5px;font-family:var(--mono);font-variant-numeric:tabular-nums;color:var(--muted)}
  #pmkCount.under{color:var(--amber)}
  #pmkCount.over{color:var(--warn);font-weight:700}
  #pmkLegBtn.on{background:var(--orange);border-color:var(--orange);color:#0B0F17}
  .phpick{margin-bottom:9px}
  .phpickrow{display:flex;align-items:center;gap:8px;margin-bottom:5px}
  .phpickrow span{flex:1;min-width:0;font-size:12px;overflow:hidden;
    text-overflow:ellipsis;white-space:nowrap}
  #pmkFoot .cols{margin:0;flex:0 0 auto}
  #pmkEdit{display:flex;align-items:center;gap:8px;flex:1 1 240px;min-width:200px}
  #pmkEdit em{flex:0 0 auto;font-style:normal;font-size:10.5px;font-weight:700;
    text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
  #pmkEdit label{flex:1 1 90px;min-width:70px;display:flex;align-items:center;gap:6px;
    font-size:10.5px;color:var(--muted)}
  #pmkEdit input[type="range"]{flex:1;min-width:52px}
  #pmkEdit input[type="range"]:disabled{opacity:.4}
  #pmkTxt{display:flex;gap:5px;flex-wrap:wrap}
  #pmkTxt[hidden]{display:none}
  #pmkTxt .btn.on{background:var(--orange);border-color:var(--orange);color:#0B0F17}
  #pmkTxt .btn:disabled{opacity:.45}
  #pmkNav{display:flex;gap:4px;margin-left:auto}
  #pmkNav .btn{min-width:38px}
  @media (max-width:1100px){
    #elev{padding:0}
    #elevCard{width:100%;height:100%;max-height:none;border-radius:0;border:0}
    #pmk{padding:0}
    #pmkCard{width:100%;height:100%;max-height:none;border-radius:0;border:0}
    #pmkTop{padding-top:calc(12px + env(safe-area-inset-top));
      padding-left:calc(14px + env(safe-area-inset-left));
      padding-right:calc(14px + env(safe-area-inset-right))}
    #pmkFoot{padding-bottom:calc(10px + env(safe-area-inset-bottom));
      padding-left:calc(14px + env(safe-area-inset-left));
      padding-right:calc(14px + env(safe-area-inset-right))}
    #elevTop{padding-top:calc(12px + env(safe-area-inset-top));
      padding-left:calc(14px + env(safe-area-inset-left));
      padding-right:calc(14px + env(safe-area-inset-right))}
    #elevArt{padding-left:calc(12px + env(safe-area-inset-left));
      padding-right:calc(12px + env(safe-area-inset-right))}
    #elevFoot{padding-bottom:calc(10px + env(safe-area-inset-bottom));
      padding-left:calc(14px + env(safe-area-inset-left));
      padding-right:calc(14px + env(safe-area-inset-right))}
    #tutTop{padding-top:calc(14px + env(safe-area-inset-top));
      padding-left:calc(16px + env(safe-area-inset-left));
      padding-right:calc(16px + env(safe-area-inset-right))}
    #tutFoot{padding-bottom:calc(12px + env(safe-area-inset-bottom));
      padding-left:calc(16px + env(safe-area-inset-left));
      padding-right:calc(16px + env(safe-area-inset-right))}
    #modal{padding-top:calc(12px + env(safe-area-inset-top));
      padding-bottom:calc(12px + env(safe-area-inset-bottom));
      padding-left:calc(12px + env(safe-area-inset-left));
      padding-right:calc(12px + env(safe-area-inset-right))}
  }

  /* ---------------------------------------------------------- site photos */
  /* #phList only holds View site photos now. The photos themselves are in
     #phGal. The thumbnails are object URLs off the Blob, made and revoked in
     photos.js, so nothing here may cache them. */
  #phList{display:flex;flex-direction:column;gap:8px;margin-bottom:10px}
  .phcap{width:100%;box-sizing:border-box;font:inherit;font-size:12px;
    background:var(--ink);color:var(--text);border:1px solid var(--line-2);
    border-radius:5px;padding:5px 7px}
  .phcap:focus{outline:none;border-color:var(--orange)}
  .btn:disabled{opacity:.42;cursor:default}

  /* ------------------------------------------------ photo picker, gallery */
  /* #phPick and #phGal share one card: .phover, .phcard, .phtop, .phnote and
     .phgrid. A tile's preview is an img with the markup svg laid over it at
     inset 0. The img is object-fit:contain and photos.js writes the svg as
     xMidYMid meet, which centre the same way. Change one and the marks slide
     off the picture. .on is toggled from photos.js.
     Rows are max-content and the art and foot never shrink. A tile is
     overflow:hidden, so a grid taller than the card squashes every row to fit
     rather than scrolling, and the name and buttons get cut off. */
  .phover{position:fixed;inset:0;background:rgba(24,21,19,.82);display:grid;place-items:center;z-index:61;padding:18px}
  .phover[hidden]{display:none}
  .phcard{background:var(--panel);border:1px solid var(--line);border-radius:14px;
    width:min(1480px,100%);height:100%;display:flex;flex-direction:column;overflow:hidden}
  .phtop{display:flex;align-items:center;gap:8px;padding:12px 14px;border-bottom:1px solid var(--line)}
  .phtop b{font-size:14px;font-weight:700}
  .phnote{margin-right:auto;margin-left:6px;font-size:12px;color:var(--muted)}
  .phgrid{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:14px;
    display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));grid-auto-rows:max-content;
    gap:14px;align-content:start}
  .phtile{appearance:none;display:flex;flex-direction:column;padding:0;text-align:left;cursor:pointer;
    background:var(--panel-2);border:2px solid var(--line);border-radius:10px;overflow:hidden;color:var(--text);font:inherit}
  .phtile:hover{border-color:var(--line-2)}
  .phtile:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
  .phtile.on{border-color:var(--orange);box-shadow:0 0 0 1px var(--orange)}
  .phtileArt{position:relative;display:block;flex:0 0 auto;width:100%;aspect-ratio:4/3;background:var(--ink)}
  button.phtileArt{appearance:none;border:0;padding:0;margin:0;cursor:pointer;font:inherit;color:inherit}
  .phtileArt img,.phtileArt .phmk{position:absolute;inset:0;width:100%;height:100%;display:block}
  .phtileArt img{object-fit:contain}
  .phtileArt .phmk{pointer-events:none}
  .phtileMiss{position:absolute;inset:0;display:grid;place-items:center;color:var(--muted);font-size:13px}
  .phtag{position:absolute;left:8px;top:8px;font-style:normal;font-size:11px;font-weight:700;
    padding:3px 8px;border-radius:5px;background:rgba(10,15,23,.85);color:var(--text)}
  .phtag.mk{top:auto;bottom:8px;background:var(--orange);color:#0B0F17}
  .phtick{position:absolute;right:8px;top:8px;width:26px;height:26px;border-radius:50%;
    border:2px solid rgba(255,255,255,.85);background:rgba(10,15,23,.5)}
  .phtile.on .phtick{background:var(--orange);border-color:var(--orange)}
  .phtile.on .phtick::after{content:"";position:absolute;left:8px;top:3px;width:6px;height:12px;
    border:solid #0B0F17;border-width:0 3px 3px 0;transform:rotate(45deg)}
  .phtileFoot{display:flex;flex-direction:column;flex:0 0 auto;gap:5px;padding:9px 11px 10px}
  .phtileFoot b{font-size:12.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .phtileSays{font-size:11.5px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .phtile.on .phtileSays{color:var(--orange)}
  /* the gallery tile is not a button, only its picture is */
  .phtile.gal{cursor:default}
  .phtile.gal:hover{border-color:var(--line)}
  .phgalBtns{display:flex;flex-wrap:wrap;gap:5px;margin-top:2px}
  .phgalBtns .btn{flex:1 1 auto}
  .phgalHead{grid-column:1/-1;display:flex;align-items:center;gap:10px;padding:6px 2px 0;
    border-bottom:1px solid var(--line);padding-bottom:8px}
  .phgalHead:not(:first-child){margin-top:10px}
  .phgalHead b{font-size:13.5px;color:var(--orange)}
  .phgalHead span{font-size:12px;color:var(--text)}
  .phgalHead em{margin-left:auto;font-style:normal;font-size:11.5px;color:var(--muted)}
  .phgalEmpty{grid-column:1/-1;color:var(--muted);font-size:13px;padding:30px;text-align:center}

  /* ------------------------------------------------------- cloud jobs */
  /* #cloud reuses the photo card: .phover, .phcard, .phtop and .phnote. Only
     the body is its own, because a job list is rows and not a grid of tiles.
     The lock and the list are never both up, cloud.js swaps them with hidden,
     so both are laid out as if they own the whole card. */
  .cloudlist{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:14px;
    display:flex;flex-direction:column;gap:8px}
  .cloudlist[hidden]{display:none}
  .cloudrow{display:flex;align-items:center;gap:12px;padding:10px 12px;
    background:var(--panel-2);border:2px solid var(--line);border-radius:10px}
  .cloudrow.on{border-color:var(--orange)}
  .cloudWho{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}
  .cloudWho b{font-size:13.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .cloudWho span{font-size:12px;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .cloudWho em{font-style:normal;font-size:11.5px;color:var(--muted)}
  .cloudrow.on .cloudWho em{color:var(--orange)}
  .cloudBtns{display:flex;gap:6px;flex:0 0 auto}
  .cloudEmpty{color:var(--muted);font-size:13px;padding:30px;text-align:center}
  .cloudlock{flex:1;min-height:0;overflow-y:auto;padding:24px 16px;
    display:flex;flex-direction:column;align-items:center;gap:10px}
  .cloudlock[hidden]{display:none}
  .cloudlock label{display:flex;flex-direction:column;gap:5px;width:min(320px,100%);font-size:12.5px}
  .cloudlock .hint{max-width:360px;text-align:center;margin:0}
  #cloudErr:not(:empty){color:var(--orange)}
  .cloudfoot{flex:0 0 auto;padding:10px 14px;border-top:1px solid var(--line);display:flex;justify-content:flex-end}
  /* the row's preview button. The picture is loaded by cloud.js into the img,
     so the word under it is what shows until one arrives and for a job saved
     before previews existed. */
  .cloudShot{appearance:none;position:relative;flex:0 0 auto;width:104px;height:74px;padding:0;
    border:1px solid var(--line);border-radius:7px;overflow:hidden;cursor:pointer;
    background:var(--ink);color:var(--muted);font:inherit;font-size:11px;
    display:grid;place-items:center}
  .cloudShot:hover{border-color:var(--orange)}
  .cloudShot:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
  .cloudShot img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
  .cloudprev{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:14px;
    display:grid;grid-template-columns:minmax(0,1.6fr) minmax(240px,1fr);gap:14px;align-content:start}
  .cloudprev[hidden]{display:none}
  .cloudprevArt{position:relative;background:var(--ink);border:1px solid var(--line);
    border-radius:10px;overflow:hidden;aspect-ratio:1587/1123;display:grid;place-items:center}
  .cloudprevArt img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;display:block}
  .cloudprevArt span{color:var(--muted);font-size:12.5px;padding:20px;text-align:center}
  .cloudprevSide{display:flex;flex-direction:column;gap:10px;min-width:0}
  .cloudprevSide>b{font-size:15px;font-weight:700}
  .cloudprevInfo{display:flex;flex-direction:column;gap:1px}
  .cloudFact{display:flex;gap:10px;padding:5px 0;border-bottom:1px solid var(--line);font-size:12.5px}
  .cloudFact b{flex:0 0 84px;font-weight:600;color:var(--muted)}
  .cloudFact span{min-width:0;word-break:break-word}
  .cloudprevBtns{display:flex;flex-direction:column;gap:6px;margin-top:4px}
  /* ---------------------------------------------------------------- gate */
  /* #gate is in the html with no hidden attribute, so it paints on the first
     frame and the tool is never on screen to someone who is not signed in.
     auth.js sets hidden once there is a session. Give it display:none here by
     default and a slow connection shows a blank screen instead of a sign in
     box, which reads as broken. */
  /* html carries .gated from the markup, so nothing of the tool is readable
     until there is a session. auth.js takes the class off once /me answers.
     A sign out reloads, so it comes back on.

     visibility, NOT display. fit() in app.js sizes the sheet off
     desk.clientWidth, and the boot runs it while this class is still on. With
     display:none that measures zero and the sheet loads at minimum zoom, a
     postage stamp in the corner. visibility:hidden keeps the layout, so
     everything measures the same as it will once the class comes off.
     Anything else that measures on boot depends on this too. */
  .gated #topbar, .gated #rail, .gated #tally, .gated #desk, .gated #tabbar,
  .gated #fab, .gated #armchip, .gated #pages{visibility:hidden !important}
  #gate{position:fixed;inset:0;z-index:200;background:var(--chrome);
        display:grid;place-items:center;padding:18px;overflow-y:auto}
  #gate[hidden]{display:none}
  .gatecard{width:100%;max-width:360px;background:var(--panel);
            border:1px solid var(--line);border-radius:14px;padding:22px}
  .gatebrand{margin-bottom:18px}
  .gatebrand b{display:block;font-size:17px}
  .gatebrand span{display:block;font-size:11px;color:var(--muted);margin-top:2px}
  .gfield{margin-bottom:12px}
  .gfield[hidden]{display:none}
  .gfield label{display:block;font-size:11px;color:var(--muted);margin-bottom:4px}
  .gfield input{width:100%;box-sizing:border-box}
  .ghelp{display:block;font-size:11px;color:var(--muted);margin-top:4px}
  .btn.wide{width:100%;justify-content:center;margin-top:4px}
  .btn.link{background:none;border:0;color:var(--muted);padding:6px 0;
            text-decoration:underline;cursor:pointer}
  .btn.link:hover{color:var(--text)}
  .gateswap{margin-top:12px;text-align:center}
  #gateErr.bad{color:var(--warn)}
  .gatecard[aria-busy="true"]{opacity:.6;pointer-events:none}

  /* the account card rides on .phover and .phcard, only its body is its own */
  .acctbody{padding:14px}
  .acctrow{display:flex;gap:12px;align-items:baseline;padding:8px 0;
           border-bottom:1px solid var(--line)}
  .acctrow:last-of-type{border-bottom:0}
  /* display:flex above beats the hidden attribute on its own, so say it here.
     Without this the company switcher shows for someone in one company. */
  .acctrow[hidden]{display:none}
  /* a failure reported inside a card, where it can actually be read */
  .phnote.bad{color:var(--warn)}
  .acctlbl{flex:0 0 92px;font-size:11px;color:var(--muted)}
  .acctrow em{display:block;font-style:normal;font-size:11px;color:var(--muted);margin-top:1px}
  .acctrow select{flex:1}
  .acctfoot{margin-top:14px}
  .acctfoot .hint{margin-top:8px}

  /* ------------------------------------------------- the business card */
  /* #admin rides on .phover and .phcard like #acct and #cloud, and its rows
     reuse .cloudWho and .cloudBtns so a name, a role and two buttons line up
     the same in both. Only the tab strip and the row shell are its own.
     A tab body is swapped with the hidden attribute, and display:flex beats
     that on its own, so .admbody[hidden] is spelled out below. */
  .admtabs{flex:0 0 auto;display:flex;gap:6px;padding:10px 14px;
    border-bottom:1px solid var(--line);overflow-x:auto}
  .admtabs .btn.on{border-color:var(--orange);color:var(--orange)}
  /* overflow-y:auto alone computes overflow-x to auto as well, which turns any
     row a pixel too wide into a sideways scrollbar. Say x explicitly. */
  .admbody{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;
    overscroll-behavior:contain;padding:14px;
    display:flex;flex-direction:column;gap:10px}
  .admbody[hidden]{display:none}
  .admform{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap}
  .admform[hidden]{display:none}
  .admform .gfield{flex:1 1 200px;min-width:0;margin:0}
  .admform .gfield.admnarrow{flex:0 1 200px}
  .admform .gfield select{width:100%;box-sizing:border-box}
  .admform .btn{flex:0 0 auto}
  .admhead{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;
    margin-top:4px}
  .admhead[hidden]{display:none}
  .admlist{display:flex;flex-direction:column;gap:8px}
  /* wrap on purpose, at every width. A row holds a name of any length, a
     select and a button, and a button that will not fit belongs on the next
     line, never off the edge of the card. */
  .admrow{display:flex;align-items:center;gap:12px;padding:10px 12px;flex-wrap:wrap;
    background:var(--panel-2);border:2px solid var(--line);border-radius:10px}
  .admrow.on{border-color:var(--orange)}
  .admrow .cloudWho{flex:1 1 240px}
  .admrow .cloudWho b{white-space:normal}
  .admrow .cloudBtns{flex-wrap:wrap}
  .admtag{font-size:11.5px;color:var(--muted);align-self:center}
  /* THE ONE THAT BIT. Line 227 sets width:100% on every select in the app.
     In a flex row that makes the select fill its container and the container
     size to the select alone, so the button beside it hung off the card with
     no scrollbar to reach it. Any select put in a flex row needs this. */
  .admrole{flex:0 0 auto;width:auto}
  /* the fallback when Resend refused the invite email */
  .admcopy{display:flex;gap:8px;align-items:center;flex-wrap:wrap;padding:10px 12px;
    background:var(--panel-2);border:2px solid var(--orange);border-radius:10px}
  .admcopy[hidden]{display:none}
  .admcopy b{flex:1 1 100%;font-size:12.5px;font-weight:600}
  .admcopy input{flex:1 1 220px;min-width:0;box-sizing:border-box;font-size:12px}
  .admcopy em{flex:1 1 100%;font-style:normal;font-size:11.5px;color:var(--muted)}
  /* the branding tab. Two tiles, each the shape of the thing it holds, so a
     wide logo and a square icon are never judged in the wrong frame. The
     chequer says transparent, which is what a logo wants and an icon usually
     does not. */
  .brandrow{display:flex;gap:14px;align-items:flex-start;flex-wrap:wrap;padding:12px;
    background:var(--panel-2);border:2px solid var(--line);border-radius:10px}
  .brandart{flex:0 0 auto;display:grid;place-items:center;border:1px solid var(--line);
    border-radius:8px;overflow:hidden;color:var(--muted);font-size:11.5px;text-align:center;
    padding:6px;box-sizing:border-box;
    background-color:var(--field);
    background-image:linear-gradient(45deg,var(--panel-2) 25%,transparent 25%,transparent 75%,var(--panel-2) 75%),
                     linear-gradient(45deg,var(--panel-2) 25%,transparent 25%,transparent 75%,var(--panel-2) 75%);
    background-size:14px 14px;background-position:0 0,7px 7px}
  .brandart.wide{width:245px;height:63px}
  .brandart.square{width:64px;height:64px}
  .brandart img{max-width:100%;max-height:100%;object-fit:contain;display:block}
  .brandside{flex:1 1 260px;min-width:0;display:flex;flex-direction:column;gap:6px}
  .brandside b{font-size:13.5px;font-weight:600}
  .brandside .hint{margin:0}
  .brandbtns{display:flex;gap:6px;flex-wrap:wrap;margin-top:2px}
  #admin[aria-busy="true"] .admbody{opacity:.55;pointer-events:none}

  #brand #acctBtn{margin-left:auto;flex:0 0 auto}
  #coChip{cursor:pointer}
  /* AI credit, third line of the brand block. [hidden] is spelled out because
     the #brand span rule above sets display. */
  #creditChip{cursor:pointer}
  #creditChip[hidden]{display:none}
  #creditChip.low{color:var(--warn)}

  @media (max-width:1100px){
    .phover{padding:0}
    .phcard{border-radius:0;border:0}
    /* the gate is the only thing on screen on a phone, so give it the lot */
    #gate{padding:0;place-items:stretch}
    .gatecard{max-width:none;border-radius:0;border:0;
              padding:calc(22px + env(safe-area-inset-top)) 18px 18px}
    .phtop{flex-wrap:wrap;padding-top:calc(12px + env(safe-area-inset-top));
      padding-left:calc(14px + env(safe-area-inset-left));
      padding-right:calc(14px + env(safe-area-inset-right))}
    .phtop b{margin-right:auto}
    .phnote{order:3;flex:1 1 100%;margin:0}
    .phgrid{grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px;padding:10px;
      padding-bottom:calc(10px + env(safe-area-inset-bottom))}
    #phGalGrid{grid-template-columns:repeat(auto-fill,minmax(min(100%,280px),1fr))}
    .cloudlist{padding:10px}
    .admbody{padding:10px;padding-bottom:calc(10px + env(safe-area-inset-bottom))}
    .admform{flex-direction:column;align-items:stretch}
    .admform .btn{width:100%;justify-content:center}
    .brandrow{padding:10px}
    .brandbtns .btn{flex:1 1 auto}
    .admrow{flex-wrap:wrap}
    .admrow .cloudBtns{flex:1 1 100%}
    .admrow .cloudBtns .btn,.admrow .cloudBtns select{flex:1 1 auto}
    .cloudrow{flex-wrap:wrap}
    .cloudBtns{flex:1 1 100%}
    .cloudBtns .btn{flex:1 1 auto}
    .cloudfoot{padding-bottom:calc(10px + env(safe-area-inset-bottom))}
    .cloudShot{width:76px;height:54px}
    .cloudprev{grid-template-columns:1fr;padding:10px;
      padding-bottom:calc(10px + env(safe-area-inset-bottom))}
  }
