/* ==========================================================================
   THE ADVANCED SKIN — soft depth, done as RELIEF. Opt-in, off by default.
   ==========================================================================

   Franklin picked this from four versions of the same three screens
   (2026-09-26), after the previous one came back with: "I don't want a glowing
   effect around everything."

   WHAT THIS REPLACES, AND WHY IT GLOWED. The first build followed
   setproduct.com's neumorphism guide literally, and two of its rules fight
   each other:

     ONE HUE across the whole screen — page, card and button the same colour,
       so that depth is the ONLY thing separating them.
     BLUR IS ABOUT TWICE THE OFFSET — a card wore -6px -6px 16px #ffffff.

   Put those together and the shadow has to carry the entire message, so it
   has to be big and bright; and a pure white blurred 16px has NO EDGE
   ANYWHERE IN IT. The eye reads a hard line as an object's boundary. With no
   line in it, a soft bright shape is read as light coming OFF something rather
   than as something. That is the glow, and it was on every card, button and
   chip on the screen. It was not a tuning problem.

   THE RECIPE NOW, and every value in this file follows from it:

     TONE SEPARATES, SHADOW CONFIRMS. The page drops half a step (#dcd7c7) and
       surfaces come up half a step (#f3f0e6 -> #e8e4d6). What is raised is
       legible before any shadow is drawn — which is what frees the shadows to
       be quiet. This is the guide's one-hue rule broken on purpose, and it is
       the whole of the difference.
     A RAISED FACE IS A GRADIENT, lighter at the top. A real convex surface
       catches more light where it turns toward the source; a flat fill under
       a shadow reads as a sticker.
     THREE THIN SHADOWS, NOT ONE WIDE ONE — the way a real object sits on a
       surface: a CONTACT shadow (0 1px 2px, tight and dark, where it touches),
       a KEY shadow (0 6px 14px -4px, short and directional), and the ambient
       that the negative spread leaves behind.
     PLUS A BEVEL: inset 0 1px 0, with ZERO BLUR. One crisp pixel on the top
       lip. That single hard line is what makes a control look machined
       instead of inflated, and it is what the first build had missing
       altogether.
     LIGHT SOURCE FROM ABOVE, on every element, no exceptions.
     RADIUS 16 on a card, 12 on a button, 50% on a round control.
     COLOUR APPEARS ONCE, as a single accent — the brand amber.

   DEPTH STILL SAYS WHAT A THING IS, which is the part of the old build that
   was working and is kept unchanged:

     RAISED  = an object sitting on the page. A card, a button, a day with
               work on it.
     CARVED  = a container things sit inside, or a hole. The calendar grid, a
               budget track, an input, the inactive half of a segmented
               control.
     FLAT    = data. A table row is not an object and does not get a shadow.

   WHAT IS KEPT FROM THE FLAT THEME, because a shadow-only control is
   indistinguishable from a surface:

     1. Every control carries a real 1px --nm-edge border, 3.58:1 on the
        darkest surface in the skin.
     2. The primary action keeps its solid amber fill. A customer looking for
        the one button on the page does not hunt for it by its shadow.
     3. Text is measured, not inherited — and now measured against the DARKEST
        of the three surfaces rather than against a single base.

   scripts/test-skin-advanced.mjs measures all of it. Nothing here applies
   without [data-skin="advanced"] on <html>, so the default look is not at
   risk: with no attribute this file is inert.
   ========================================================================== */

html[data-skin="advanced"] {
  /* ------------------------------------------------------------------ RELIEF
     Franklin chose this one from four (2026-09-26), after the first attempt
     came back: "I don't want a glowing effect around everything."

     HE WAS RIGHT, AND THE CAUSE WAS ONE LINE. The guide's rule is "blur is
     about twice the offset", so a raised card wore
     `-6px -6px 16px #ffffff` — PURE WHITE, blurred 16px. There is no edge
     anywhere in that shape. The eye reads a hard line as an object's boundary;
     a 16px gaussian has no line in it, so the brain reads it as light coming
     OFF the thing rather than as a thing. That is the glow, and it was on
     every card, every button and every chip on the screen.

     WHAT A REAL OBJECT GIVES THE EYE is three thin shadows, not one wide one:
     a CONTACT shadow, tight and dark where it meets the surface; a KEY shadow,
     short and directional; an AMBIENT, wide and faint. Plus the part this skin
     had missing altogether — a BEVEL: one pixel of highlight on the top lip,
     with ZERO blur. That single crisp line is what makes a control look
     machined instead of inflated.

     AND RELIEF BREAKS THE ONE-HUE RULE ON PURPOSE. The guide insists page and
     card are the same colour and lets depth do all the separating. That is the
     rule that forces the shadows to be loud, because they are the only thing
     carrying the message. Here the page drops half a step and surfaces come up
     half a step, so TONE says what is raised before any shadow does — and the
     shadows are then free to be quiet. It is what shipped soft-UI actually
     looks like, and it is why nothing here has to glow to be seen.
     ------------------------------------------------------------------------ */

  /* The ground, and two surfaces that sit off it. A raised thing is also a
     GRADIENT, light at the top: a real convex face catches more light where it
     turns toward the source, and a flat fill under a shadow reads as a sticker.
     --nm-base is the same surface as a flat colour, for the handful of tokens
     downstream that need a colour rather than a paint. */
  --nm-page: #dcd7c7;
  --nm-base: #ede9de;
  --nm-face: linear-gradient(#f3f0e6, #e8e4d6);
  --nm-sunk: linear-gradient(#d2ccba, #dcd7c7);

  /* Kept because three rules outside this block still paint with them — the
     rail's and the header's single-sided lift, and the figures' gauge track.
     NEITHER IS PURE ANY MORE: #ffffff is what glowed. */
  --nm-light: #f6f3ea;
  --nm-dark: #c5bda9;

  /* The hairline ON a raised surface: shape, not a boundary you could measure
     (1.4:1 — it is not asked to be one). --nm-edge is the boundary, and it
     clears 3:1 on every surface in this skin, the darkest included. */
  --nm-rim: #bcb49d;
  --nm-edge: #6b6656;   /* 3.58:1 on #d2ccba, the darkest surface anything lands on */

  /* THE THREE LAYERS, plus the bevel. Written out rather than hidden behind
     more tokens so that the numbers are readable here and measurable by
     scripts/test-skin-advanced.mjs. */
  --nm-out:    inset 0 1px 0 #fffdf6, 0 1px 2px rgba(70, 64, 48, 0.22), 0 6px 14px -4px rgba(70, 64, 48, 0.16);
  --nm-out-sm: inset 0 1px 0 #fffdf6, 0 1px 2px rgba(70, 64, 48, 0.20), 0 3px 6px -2px rgba(70, 64, 48, 0.15);
  --nm-out-lg: inset 0 1px 0 #fffdf6, 0 1px 2px rgba(70, 64, 48, 0.22), 0 10px 22px -6px rgba(70, 64, 48, 0.18);
  --nm-in:     inset 0 2px 5px rgba(70, 64, 48, 0.24);
  --nm-in-sm:  inset 0 2px 4px rgba(70, 64, 48, 0.26);

  --bg: var(--nm-page);
  --bg-alt: #e4dfd0;
  --card-bone: var(--nm-base);
  --surface: var(--nm-base);

  /* A hairline between table rows. Not a control boundary — that is
     --nm-edge — so it is allowed to be quiet. */
  --line: #d5cfbf;

  /* TEXT, RE-MEASURED FOR RELIEF. Three surfaces now exist where there was
     one, so every pair has to clear on the DARKEST of them (#d2ccba, the top
     of a carved well — which is where an inactive sub-tab's label sits). That
     is what moved --muted: the old #545a50 was 5.50:1 on the single old base
     and only 4.43:1 here, i.e. under AA on the one surface nobody would have
     thought to check. */
  --ink: #22261f;        /* 9.59:1 on the darkest, 13.49:1 on a card */
  --muted: #4f554b;      /* 4.79:1 on the darkest, 6.02:1 on a card */
  --accent-ink: #6f4d03; /* 4.78:1 — the "Pending"/"Due" chip */
  --ok: #1f5a22;         /* 5.14:1 — the "Paid"/"Approved" chip */
  --danger: #8f2020;     /* 5.46:1 */

  --shadow-1: var(--nm-out-sm);
  --shadow-2: var(--nm-out);
  --shadow-3: var(--nm-out-lg);

  --radius-sm: 12px;  /* a button */
  --radius: 16px;     /* a card */
  --radius-lg: 20px;

  /* HOW FAR EACH SHADOW REACHES PAST ITS OWN EDGE. A blur of r fades over r
     centred on the edge, so it spills r/2 outward; a negative spread pulls
     that back, and the offset carries it further on the shaded side. The
     widest layer of each is what counts:

         --nm-out      6 + 14/2 - 4 =  9px  ->  16px
         --nm-out-sm   3 +  6/2 - 2 =  4px  ->   8px
         --nm-out-lg  10 + 22/2 - 6 = 15px  ->  24px

     Every one of these got SMALLER when the glow went, because a tight shadow
     does not need a wide gutter. The clearances stay where they are — they are
     a floor, and the spacing they buy is worth keeping — and
     test-skin-advanced.mjs recomputes the three sums from the offsets and
     blurs above and fails if a clearance ever stops covering its shadow. */
  --nm-clear: 16px;
  --nm-clear-sm: 8px;
  --nm-clear-lg: 24px;
}

/* ==========================================================================
   RAISED — objects sitting on the page.
   ========================================================================== */
html[data-skin="advanced"] body,
html[data-skin="advanced"] .app-col {
  background: var(--nm-page);
}

html[data-skin="advanced"] .card,
html[data-skin="advanced"] .panel,
html[data-skin="advanced"] .est-card,
html[data-skin="advanced"] .job-card,
html[data-skin="advanced"] .hist-card,
html[data-skin="advanced"] .signed-card,
html[data-skin="advanced"] .acct-card,
html[data-skin="advanced"] .cmp-col,
html[data-skin="advanced"] .cmp-panel,
html[data-skin="advanced"] .pv-panel,
html[data-skin="advanced"] .pin-card,
html[data-skin="advanced"] .pin-sheet,
html[data-skin="advanced"] .cal-day-panel,
html[data-skin="advanced"] .empty-state,
html[data-skin="advanced"] .start-opt,
html[data-skin="advanced"] .table-wrap {
  background: var(--nm-face);
  border: 1px solid var(--nm-rim);
  border-radius: var(--radius);
  box-shadow: var(--nm-out);
}

/* ---- A CARD HAS TO HAVE ROOM IN IT ----
 *
 * Franklin, 2026-09-26, with a photograph of the New Estimate screen: "here I
 * have circled a box where the words are very close to the edge, if not
 * extruding past the edge of the box therein. I actually noticed this quite
 * often when I am going through the software on different account versions in
 * different pages and tabs."
 *
 * He was seeing one cause in several places. The block above gives fifteen
 * classes a background, a radius and a shadow — it turns them into OBJECTS —
 * and some of them have no padding of their own, because in the Original look
 * they are not objects and never needed any. `.empty-state` is a sentence;
 * `.cmp-panel` is a layout box. Promoted to cards with nothing inside them,
 * each printed its text flat against its own edge, on every screen that used
 * it, which is why he kept meeting it.
 *
 * The padding lives HERE, with the rule that makes the card, rather than in
 * the base rules where the next person to promote a sixteenth class would not
 * find it.
 *
 * Only the ones whose CONTENT would be flush, which is not the same as the
 * ones with padding: 0. `.table-wrap` reads as an offender and is not — the
 * `.data-table td` inside it already carries 16px, and padding the wrapper as
 * well would take 32px off a 343px phone pane for nothing. `.cal-day-panel`
 * is a top border and no box at all, and its list items pad themselves.
 * Measured before changing, both times. `.pv-panel` is flush in BOTH looks,
 * so its padding is in portal.css rather than here.
 *
 * See scripts/test-skin-padding.mjs, which fails if a class is ever added to
 * the block above without room coming from somewhere. */
html[data-skin="advanced"] .empty-state,
html[data-skin="advanced"] .cmp-panel {
  padding: var(--space-4);
}

/* The rail and the header are the page's own edges rather than objects on it,
   so they take a single-sided lift. A rail that appears to float free of the
   window reads as a dropped panel. */
html[data-skin="advanced"] .app-side,
html[data-skin="advanced"] .cp-side {
  background: var(--nm-base);
  border-right: none;
  box-shadow: 10px 0 20px -10px var(--nm-dark);
}
/* THE BRAND BAR KEEPS ITS COLOUR — no background here. An earlier version
   repainted it with the light base while its label stayed --on-brand, the
   near-white picked to sit on forest: the company's name, unreadable, at the
   top of every staff screen. test-skin-advanced.mjs now fails if a background
   reappears in this rule. A skin changes how surfaces are drawn, not what the
   company's colour is. */
html[data-skin="advanced"] .app-header {
  border-bottom: none;
  box-shadow: 0 10px 20px -12px var(--nm-dark);
  /* Room for the shadow it casts. `0 10px 20px -12px` reaches 20/2 - 12 + 10 =
     8px below the bar, and on a phone .app-content drops its padding to nothing
     (see the narrow block at the end of portal.css), which put the page's own
     <h1> — "Account", "Products & prices", "Accessibility" — flush against the
     bar and therefore inside that fade. Only ever visible at phone width,
     which is where the sweep is worth running. The full --nm-clear rather than
     the 8px the arithmetic asks for: the heading's own line box starts a pixel
     above where the text does, and 8px left it 1.0px inside the fade — near
     enough is not a measurement. */
  margin-block-end: var(--nm-clear);
}

/* ==========================================================================
   CARVED — containers, holes, and the inactive half of a control.
   ========================================================================== */

/* THE CALENDAR, and the decision the mockup turned on. The month grid is the
   carved thing and the days sit inside it. Thirty-five extruded tiles all
   competing is the classic neumorphism failure — it turns a month to gravel —
   so only a day that HAS WORK on it is raised, and an empty day stays flat.
   That also makes "nothing booked" readable at a glance, which is the
   question somebody actually opens this screen to answer. */
html[data-skin="advanced"] .cal-grid {
  background: var(--nm-sunk);
  border: 1px solid #c9c2b0;
  border-radius: var(--radius);
  box-shadow: var(--nm-in);
  gap: 8px;
  padding: 12px;
}
html[data-skin="advanced"] .cal-head {
  background: none;
  box-shadow: none;
}
html[data-skin="advanced"] .cal-cell {
  background: none;
  border-radius: 13px;
  box-shadow: none;
}
/* `:has` is what lets the stylesheet ask "is there work on this day" without
   the calendar's renderer having to add a class for it. Where it is
   unsupported every cell simply stays flat, which is the old look, not a
   broken one. */
html[data-skin="advanced"] .cal-cell:has(.cal-chip) {
  background: var(--nm-face);
  border: 1px solid var(--nm-rim);
  box-shadow: var(--nm-out-sm);
}
html[data-skin="advanced"] .cal-cell.out { background: none; box-shadow: none; }
html[data-skin="advanced"] .cal-cell.picked {
  outline: none;
  box-shadow: var(--nm-in-sm), 0 0 0 2px var(--accent-ink);
}
html[data-skin="advanced"] .cal-lane-cell {
  background: none;
  box-shadow: none;
}
html[data-skin="advanced"] .cal-lane-cell:has(.cal-chip) {
  background: var(--nm-face);
  border: 1px solid var(--nm-rim);
  border-radius: 10px;
  box-shadow: var(--nm-out-sm);
}

/* A BUDGET TRACK IS A TROUGH, which is exactly what an inset shadow draws —
   the one place this style is straightforwardly better than a flat bar. The
   fill is the single accent riding in it, with a hairline drop so it reads as
   sitting IN the channel rather than painted on top of it. */
html[data-skin="advanced"] .jb-track,
html[data-skin="advanced"] .bar-track {
  background: var(--nm-sunk);
  border-radius: 999px;
  box-shadow: var(--nm-in-sm);
}
html[data-skin="advanced"] .jb-fill,
html[data-skin="advanced"] .bar-fill {
  border-radius: 999px;
  box-shadow: 1px 1px 3px rgba(19, 32, 24, 0.22);
}

/* Banners and small panels that hold something rather than being something. */
html[data-skin="advanced"] .jb-booked,
html[data-skin="advanced"] .delivery-box,
html[data-skin="advanced"] .gap-note {
  background: var(--nm-sunk);
  border: 1px solid #c9c2b0;
  border-radius: 14px;
  box-shadow: var(--nm-in-sm);
}

/* Inputs are wells. A field reads as somewhere to put something, which is the
   other place the idiom genuinely helps. The fill stays the base so --ink and
   --muted keep the ratios measured above. */
html[data-skin="advanced"] input[type="text"],
html[data-skin="advanced"] input[type="search"],
html[data-skin="advanced"] input[type="email"],
html[data-skin="advanced"] input[type="tel"],
html[data-skin="advanced"] input[type="number"],
html[data-skin="advanced"] input[type="password"],
html[data-skin="advanced"] input[type="time"],
html[data-skin="advanced"] input[type="date"],
html[data-skin="advanced"] textarea,
html[data-skin="advanced"] select,
html[data-skin="advanced"] .stack input,
html[data-skin="advanced"] .pin-sheet input,
html[data-skin="advanced"] .job-search input[type="search"] {
  background: var(--nm-sunk);
  color: var(--ink);
  /* THE EDGE. The guide drops this and lets the inset shadow imply the field.
     A soft inset shadow is not a boundary you can measure, and on a tablet in
     daylight it is not one you can see either. */
  border: 1px solid var(--nm-edge);
  border-radius: var(--radius-sm);
  box-shadow: var(--nm-in-sm);
}
html[data-skin="advanced"] input:focus-visible,
html[data-skin="advanced"] textarea:focus-visible,
html[data-skin="advanced"] select:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 2px;
}

/* ==========================================================================
   CONTROLS.
   ========================================================================== */

/* Secondary buttons: raised, a real border, and 12px rather than the pill the
   old skin used — the guide gives buttons their own radius, and a rounded
   rectangle reads as a key while a pill reads as a tag. */
html[data-skin="advanced"] .btn-sm,
html[data-skin="advanced"] .hist-filters button,
html[data-skin="advanced"] .app-side-foot button,
html[data-skin="advanced"] .pin-buttons button,
html[data-skin="advanced"] .q-zoom-bar button,
html[data-skin="advanced"] .details-btn {
  background: var(--nm-face);
  color: var(--ink);
  border: 1px solid var(--nm-edge);
  border-radius: var(--radius-sm);
  box-shadow: var(--nm-out-sm);
  transition: box-shadow var(--dur-fast) var(--ease);
}
html[data-skin="advanced"] .btn-sm:hover,
html[data-skin="advanced"] .hist-filters button:hover,
html[data-skin="advanced"] .app-side-foot button:hover,
html[data-skin="advanced"] .pin-buttons button:hover,
html[data-skin="advanced"] .q-zoom-bar button:hover,
html[data-skin="advanced"] .details-btn:hover {
  box-shadow: var(--nm-out);
}
/* Pressing pushes it INTO the page. The whole point of the idiom. */
html[data-skin="advanced"] .btn-sm:active,
html[data-skin="advanced"] .hist-filters button:active,
html[data-skin="advanced"] .app-side-foot button:active,
html[data-skin="advanced"] .pin-buttons button:active,
html[data-skin="advanced"] .q-zoom-bar button:active,
html[data-skin="advanced"] .details-btn:active {
  box-shadow: var(--nm-in-sm);
}

/* A SEGMENTED CONTROL: the strip is carved and only the chosen tab is raised
   out of it. This is the mockups' clearest single idea — selection becomes a
   physical position rather than a colour swap, so a row of tabs is scannable
   at a glance without reading any of them. */
html[data-skin="advanced"] .sub-tabs {
  background: var(--nm-sunk);
  border-bottom: none;
  border-radius: 14px;
  box-shadow: var(--nm-in-sm);
  padding: 5px;
  gap: 4px;
}
html[data-skin="advanced"] .sub-tabs button {
  border: 1px solid transparent;
  border-radius: 10px;
  box-shadow: none;
  background: none;
  opacity: 1;
  color: var(--muted);
}
html[data-skin="advanced"] .sub-tabs button.active {
  background: var(--nm-face);
  border-color: var(--nm-edge);
  box-shadow: var(--nm-out-sm);
  color: var(--ink);
}
html[data-skin="advanced"] .app-nav button.active,
html[data-skin="advanced"] .hist-filters button.active {
  background: var(--nm-sunk);
  box-shadow: var(--nm-in-sm);
  border-color: var(--nm-edge);
}

/* THE BURGER — and the second time this skin has been caught doing the same
   thing to the brand bar.
   ==========================================================================
   Franklin, 2026-09-24: "the hamburger style button... does not look good in
   the advanced setting." It did not, and for a reason worth writing down,
   because the rule it breaks is the one this whole skin rests on:

       A NEUMORPHIC SURFACE ONLY WORKS AGAINST ITS OWN BASE.

   The burger lives in the forest bar, not on the cream page. The first version
   gave it `background: var(--nm-base)` and `var(--nm-out-sm)` — the page's
   base and the page's shadow pair — so on a phone you got a CREAM DISC
   floating on a dark green bar, with the three bars still wearing --on-brand,
   the near-white picked to sit on forest. Measured: #e8efe9 on #e6e2d6, which
   is 1.05:1. The icon was not faint, it was gone. And --nm-light is pure white,
   so the raised shadow bloomed into a glowing halo around the disc — a soft
   highlight reads as a lit edge on cream and as a light leak on forest.

   This is the .app-header bug again in a smaller package: that one repainted
   the bar and left its label --on-brand; this one repainted a control ON the
   bar and left its icon --on-brand. The old test caught the bar and had
   nothing to say about the things standing on it. It does now.

   THE FIX IS NOT TO GIVE UP THE IDIOM, it is to derive it from the right
   surface. The recipe says the shadow pair comes from the base the thing sits
   on — so on the brand bar the pair comes from the BRAND, and the brand
   palette already ships exactly the two tones needed: --brand-soft is forest
   lifted, --brand-deep is forest darkened. Same light source, top-left, same
   3/8 geometry as every other small control. The icon keeps --on-brand at
   9.3:1 on forest, untouched, because the bar's colour is not this skin's to
   change.

   Only ever visible below 60rem — .app-burger and .cp-burger are display:none
   on a desktop — so this is a crew-tablet and phone fix, which is where it
   was seen. */
html[data-skin="advanced"] .app-burger,
html[data-skin="advanced"] .cp-burger {
  background: var(--brand);
  border: 1px solid var(--brand-soft);
  border-radius: 50%;
  box-shadow: -3px -3px 8px var(--brand-soft), 3px 3px 8px var(--brand-deep);
}
/* Pressed, it goes INTO the bar, the same as every other control in this skin
   — with the pair still derived from the bar rather than from the page. */
html[data-skin="advanced"] .app-burger:active,
html[data-skin="advanced"] .cp-burger:active {
  box-shadow: inset -2px -2px 6px var(--brand-soft), inset 2px 2px 6px var(--brand-deep);
}
html[data-skin="advanced"] .app-burger:focus-visible,
html[data-skin="advanced"] .cp-burger:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* THE PRIMARY ACTION DOES NOT MELT. "Approve", "Pay", "Send" keep the solid
   amber with dark text on it, because the guide's own accessibility problem is
   that a shadow-only button hides, and this is the one button on a customer's
   screen that must not. */
html[data-skin="advanced"] .stack button,
html[data-skin="advanced"] .btn-sm.primary,
html[data-skin="advanced"] .btn-primary,
html[data-skin="advanced"] button.primary {
  background: var(--accent);
  color: var(--brand-deep);
  border: 1px solid var(--accent-ink);
  border-radius: var(--radius-sm);
  box-shadow: var(--nm-out-sm);
}
html[data-skin="advanced"] .stack button:hover,
html[data-skin="advanced"] .btn-sm.primary:hover,
html[data-skin="advanced"] .btn-primary:hover,
html[data-skin="advanced"] button.primary:hover {
  background: var(--accent-hover);
  box-shadow: var(--nm-out);
}
html[data-skin="advanced"] .stack button:active,
html[data-skin="advanced"] .btn-sm.primary:active,
html[data-skin="advanced"] .btn-primary:active,
html[data-skin="advanced"] button.primary:active {
  box-shadow: var(--nm-in-sm);
  transform: none;
}

/* ==========================================================================
   SWITCHES AND CHECKS — the one control the flat theme never styled.
   ==========================================================================
   Franklin, 2026-09-22, asked for toggles along with the graphs and the dials.
   Twenty-five checkboxes and seven radios across the software were whatever
   the browser felt like drawing, which on a crew tablet is a 13px square with
   a system blue tick in a portal that owns no blue.

   THE IDIOM FITS THIS ONE PERFECTLY, which is why it is worth doing here and
   nowhere else: off is a CARVED slot and on is a RAISED knob that has slid
   across it. That is the same raised-versus-carved grammar the rest of the
   skin uses to say what a thing is, and it means the state is legible as a
   POSITION, from across a truck cab, before any colour is read.

   FOUR THINGS THAT ARE NOT NEGOTIABLE, because `appearance: none` throws all
   of them away and they have to be put back by hand:

     1. STATE IS NEVER COLOUR ALONE. The knob moves. Somebody who cannot tell
        the amber from the base still sees which end it is at.
     2. THE FOCUS RING SURVIVES. :focus-visible draws the same amber ring every
        other control in this skin uses. A switch you cannot tab to is worse
        than the square it replaced.
     3. THE HIT TARGET STAYS BIG. 46x26 for a switch, 22px for a radio, both
        above the 24px minimum a finger needs, and the <label> around it keeps
        working as it always did.
     4. DISABLED LOOKS DISABLED. Half opacity and the default cursor — a
        read-only viewer pressing a live-looking switch that does nothing is
        the bug this prevents.

   Kept scoped like everything else: with no [data-skin] these are ordinary
   browser checkboxes, exactly as they are today. */

html[data-skin="advanced"] input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  box-sizing: border-box;
  position: relative;
  /* `width: 46px` and not a flex-basis: several of these sit inside labels with
     their own inline styles, and a fixed box is the one thing those cannot
     stretch. */
  width: 46px;
  min-width: 46px;
  height: 26px;
  margin: 0 var(--space-2) 0 0;
  border-radius: 999px;
  border: 1px solid var(--nm-edge);
  background: var(--nm-sunk);
  box-shadow: var(--nm-in-sm);
  cursor: pointer;
  vertical-align: -7px;
  transition: background var(--dur-fast) var(--ease);
}
/* The knob. A real raised object in the channel, lit top-left like everything
   else on the page. */
html[data-skin="advanced"] input[type="checkbox"]::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--nm-face);
  border: 1px solid var(--nm-edge);
  box-shadow: var(--nm-out-sm);
  transition: transform var(--dur-fast) var(--ease);
}
html[data-skin="advanced"] input[type="checkbox"]:checked {
  background: var(--accent);
  border-color: var(--accent-ink);
}
html[data-skin="advanced"] input[type="checkbox"]:checked::after {
  transform: translateX(20px);
}
html[data-skin="advanced"] input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 2px;
}
html[data-skin="advanced"] input[type="checkbox"]:disabled {
  opacity: 0.5;
  cursor: default;
}
/* Pressing pushes the knob in, the same as every button in this skin. */
html[data-skin="advanced"] input[type="checkbox"]:active:not(:disabled)::after {
  box-shadow: var(--nm-in-sm);
}

/* A RADIO IS A HOLE WITH SOMETHING IN IT — carved well, raised dot. Round,
   because a radio has always been round and changing that would cost more
   than the skin gains. */
html[data-skin="advanced"] input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  box-sizing: border-box;
  position: relative;
  width: 22px;
  min-width: 22px;
  height: 22px;
  margin: 0 var(--space-2) 0 0;
  border-radius: 50%;
  border: 1px solid var(--nm-edge);
  background: var(--nm-sunk);
  box-shadow: var(--nm-in-sm);
  cursor: pointer;
  vertical-align: -5px;
}
html[data-skin="advanced"] input[type="radio"]::after {
  content: '';
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: var(--nm-out-sm);
  transform: scale(0);
  transition: transform var(--dur-fast) var(--ease);
}
html[data-skin="advanced"] input[type="radio"]:checked::after { transform: scale(1); }
html[data-skin="advanced"] input[type="radio"]:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 2px;
}
html[data-skin="advanced"] input[type="radio"]:disabled { opacity: 0.5; cursor: default; }

/* Somebody who asked for more contrast gets the square back, with a real tick
   drawn in ink: position AND a mark, no reliance on the soft channel at all. */
@media (prefers-contrast: more) {
  html[data-skin="advanced"] input[type="checkbox"],
  html[data-skin="advanced"] input[type="radio"] { box-shadow: none; }
  html[data-skin="advanced"] input[type="checkbox"]::after,
  html[data-skin="advanced"] input[type="radio"]::after { box-shadow: none; }
}

/* ==========================================================================
   FLAT — data. A table row is not an object and does not get a shadow.
   ==========================================================================
   This is the honest limit of the style and the mockup drew it deliberately:
   forty rows of money cannot each be an extruded tile. The SECTION is the
   raised object (.table-wrap, above) and the rows inside it are flat, divided
   by a hairline. The style is spent on the container and the controls; the
   numbers are left alone to be read. */
html[data-skin="advanced"] .data-table tbody tr:nth-child(even) {
  background: rgba(19, 32, 24, 0.028);
}
/* Small repeated rows — a crew list, a task list — are flat too, for the same
   reason a table row is. A list of forty extrusions is gravel. */
html[data-skin="advanced"] .fu-item,
html[data-skin="advanced"] .crew-list li,
html[data-skin="advanced"] .jc-on li,
html[data-skin="advanced"] .cal-day-list li {
  background: var(--nm-sunk);
  border-color: var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--nm-in-sm);
}

/* ==========================================================================
   CLEARANCE — the gap a soft shadow needs in order to be a shadow.
   ==========================================================================
   Franklin, 2026-09-22, with a screenshot and a purple line drawn under the
   offending line of text: the last line of a panel's intro paragraph was
   sitting inside the white highlight of the card below it, so the words ran
   through a colour that was changing underneath them.

   That is arithmetic rather than taste. The flat theme could butt text
   straight up against a card because a 1px border ends where it ends; a
   14px-deep highlight does not, and the markup that was fine before —

       <h2>Bank &amp; cards</h2>
       <p class="hint">Every charge on the connected cards ...</p>
       <div id="bank-body"><div class="table-wrap"> ... </div></div>

   — leaves ZERO gap between the paragraph and the card, because .hint carries
   `margin: 0`. Measured on the live page, that paragraph's last line sat
   11.2px inside a 14px wash: not close to it, inside it, descenders and all.

   THE RULE: prose and a raised surface keep at least that surface's reach
   between them. Three declarations below cover the whole application, and they
   can all be stated without the spacing compounding anywhere they meet because
   vertical margins between siblings COLLAPSE — a paragraph with 16px below and
   a card with 16px above still make one 16px gap, never 32.

   Found and re-checked with scripts/audit-shadow-clearance.mjs, which walks
   every tab of every page in both modes, takes the real geometry of every
   shadow and every text run out of the browser, and reports any word standing
   in a wash. It found twelve places on the staff dashboard alone; eyeballing
   screenshots had found one. Depth is not visible at a glance — that is rather
   the point of it — so this is not a thing to check by looking.
   ========================================================================== */

/* Prose that introduces something. This is the one that matters: nearly every
   panel in the software is a heading, a line of explanation, and then the
   thing being explained. */
html[data-skin="advanced"] p.hint,
html[data-skin="advanced"] summary.hint {
  margin-block: var(--nm-clear);
}
/* The compare view sets this paragraph tight under its heading on purpose and
   has no card beneath it to clear. */
html[data-skin="advanced"] .cmp-head .hint {
  margin-block: 0.15rem 0;
}

/* A CARD INSIDE A CARD. .table-wrap is flat in the classic theme — a table on
   a panel does not need a second panel around it — but this skin raises it, so
   it acquires a wash of its own and needs its own room. This also covers the
   button rows that sit above and below these tables, which the paragraph rule
   above cannot reach. */
html[data-skin="advanced"] .table-wrap {
  margin-block: var(--nm-clear);
}
/* Unless the panel's own padding is already the gap. Scoped to a DIRECT child
   of the card: the customers table is the first child of a bare wrapper div
   inside the panel, with the "+ Add a new contact" button above that wrapper,
   and a plain :first-child dropped the margin and put the button back in the
   wash — 3.3px in, which the audit caught and I would not have. */
html[data-skin="advanced"] .panel > .table-wrap:first-child,
html[data-skin="advanced"] .card > .table-wrap:first-child { margin-block-start: 0; }
html[data-skin="advanced"] .panel > .table-wrap:last-child,
html[data-skin="advanced"] .card > .table-wrap:last-child { margin-block-end: 0; }

/* A SMALL CONTROL THAT WRAPS ONTO ITS OWN LINE. In a data cell on a phone
   `<span class="pay-chip">not yet</span> <button class="btn-sm">Set up</button>`
   breaks across two lines, and the button's 7px wash then covers the chip above
   it. An atomic inline's margin box counts towards the line box, so the token
   for that wash is all this needs, and it costs nothing on the rows — every
   other one — where the pair still fits on a single line. */
html[data-skin="advanced"] .data-table .btn-sm {
  margin-block-start: var(--nm-clear-sm);
}

/* AND THE GENERAL CASE, so markup written later is safe by default: any raised
   surface that follows text in normal flow keeps the gap. Cheap to state,
   impossible to forget, and it cannot disturb a grid or a flex row because it
   only fires on an adjacent sibling. */
/* One line on purpose: test-skin-advanced.mjs proves every selector in this
   file is scoped by looking for [data-skin] on the line that opens the rule,
   and a selector wrapped across lines would read to it as an unscoped one. */
html[data-skin="advanced"] :is(h1, h2, h3, h4, h5, h6, p, ul, ol, dl, summary, label, .hint) + :is(.card, .panel, .est-card, .job-card, .hist-card, .signed-card, .acct-card, .cmp-col, .cmp-panel, .pv-panel, .cal-day-panel, .empty-state, .start-opt, .table-wrap, .est-cards, .acct-cards, .cal-grid, .crew-list) {
  margin-block-start: var(--nm-clear);
}

/* ==========================================================================
   THE ESCAPE HATCHES.
   ========================================================================== */

/* Somebody who has asked their OS for more contrast has told us in advance
   that this whole aesthetic does not work for them. Honour it: the shadows go
   and real borders and distinct fills come back. The page keeps the skin's
   rounding and its measured text, so it still looks deliberate — it just
   stops using depth to say where anything is. */
@media (prefers-contrast: more) {
  html[data-skin="advanced"] {
    --surface: #fdfcf8;
    --card-bone: #fdfcf8;
    --bg-alt: #dcd6c6;
    --shadow-1: 0 1px 3px rgba(19, 32, 24, 0.07);
    --shadow-2: 0 10px 24px rgba(19, 32, 24, 0.10);
    --shadow-3: 0 20px 48px rgba(19, 32, 24, 0.16);
    --nm-out: none; --nm-out-sm: none; --nm-out-lg: none;
    --nm-in: none; --nm-in-sm: none;
  }
  html[data-skin="advanced"] .card,
  html[data-skin="advanced"] .panel,
  html[data-skin="advanced"] .est-card,
  html[data-skin="advanced"] .job-card,
  html[data-skin="advanced"] .hist-card,
  html[data-skin="advanced"] .signed-card,
  html[data-skin="advanced"] .acct-card,
  html[data-skin="advanced"] .cmp-col,
  html[data-skin="advanced"] .cmp-panel,
  html[data-skin="advanced"] .pv-panel,
  html[data-skin="advanced"] .pin-card,
  html[data-skin="advanced"] .pin-sheet,
  html[data-skin="advanced"] .table-wrap,
  html[data-skin="advanced"] .cal-grid {
    background: var(--surface);
    border: 1px solid var(--nm-edge);
  }
  html[data-skin="advanced"] .cal-cell:has(.cal-chip) { border: 1px solid var(--nm-edge); }
  html[data-skin="advanced"] .sub-tabs { border: 1px solid var(--nm-edge); }
  html[data-skin="advanced"] .app-side,
  html[data-skin="advanced"] .cp-side { border-right: 1px solid var(--nm-edge); }
  html[data-skin="advanced"] .app-header { border-bottom: 1px solid var(--nm-edge); }
}

/* Printing a quote or a contract: shadows cost toner and say nothing on paper,
   and the base tint greys a page that should be white. */
@media print {
  html[data-skin="advanced"] {
    --nm-base: #ffffff; --bg: #fff; --bg-alt: #fff; --card-bone: #fff; --surface: #fff;
    --nm-out: none; --nm-out-sm: none; --nm-out-lg: none;
    --nm-in: none; --nm-in-sm: none;
    --shadow-1: none; --shadow-2: none; --shadow-3: none;
  }
  html[data-skin="advanced"] .card,
  html[data-skin="advanced"] .panel,
  html[data-skin="advanced"] .est-card { border: 1px solid #999; }
}

/* The pipeline board: a stage is a carved channel, a deal a raised object in
   it. The column's 12px padding clears --nm-out-sm's 8px reach, and the 12px
   gap between cards does the same, so no word sits in a neighbour's shadow. */
html[data-skin="advanced"] .pl-col {
  background: var(--nm-sunk);
  border: 1px solid var(--nm-rim);
  box-shadow: var(--nm-in);
}
html[data-skin="advanced"] .pl-card {
  background: var(--nm-face);
  border: 1px solid var(--nm-rim);
  box-shadow: var(--nm-out-sm);
}

