@charset "UTF-8";
/* ----------------------------------------------------------------------------
   GSL Portal - portal.css: the one stylesheet (Sunny, 2026-10-05: "like if it can be in one
   (no-duplicates) but where you have clear sections").
   1. Tokens   2. Base   3. Layout and frame   4. Components   5. Screens   6. Utilities
   One theme (the price sheets' ink ground, cream cards, gold); layered over Bootstrap 5
   (CDN), which reads the --bs-* roles in section 1. Plain ASCII; characters a rule needs are CSS escapes.
   ---------------------------------------------------------------------------- */

/* == 1. Tokens == */
/* Every color and size is set here, once, on :root, and nowhere else in this file: raw palette,
   then Allan's alias names, then roles (what each part uses), then the size scale and type.
   Everything below reads roles (and the size scale) only. DESIGN.md maps each role to its parts. */
:root {
    color-scheme: dark;


    /* -- 1a. Raw palette -- */
    /* ---- 1. Palette (pricesheets) ---- */
    --ink0: #0B1410;
    --ink1: #0F1B15;
    --ink2: #143021;
    --ink3: #1A3A27;
    --forest: #2D5F3F;
    --forest-dk: #1A3A26;
    --GOLD: #C5A55A;
    --gold-tint: #F5EED9;
    --gold-tint-2: #EFE4C2;
    --cream4: #E4DAB9;
    --cream: #FAF6EC;
    --cream2: #F4EEDD;
    --cream3: #EDE5CE;
    --gold: #B08935;
    --gold-b: #C9A84C;
    --gold-d: #6E5620;
    --ltx: #1A2620;          /* text on cream */
    --ltx2: #4A5751;         /* muted text on cream */
    --tx: #F4EEDD;           /* text on green */
    --tx2: #B8B09A;          /* muted text on green */
    --tx3: #9C9480;
    --rule: #D9D0BC;
    --rule-s: #BEB39B;
    --danger: #8B2635;

    /* ---- 2. Medallion tones (Settings shows an app's icon on these) ---- */
    /* Icon medallions for tools without a logo (Sunny, 2026-10-05: "too much gold" on the solid disc).
       Default = quiet: gold-tint disc, thin gold ring, dark line icon. A registry row may pick a tone
       (apps.icon_color) from Allan's heritage colors: a deep disc with a cream icon. */
    --tone-forest: #2D5F3F;  /* cream icon 6.9:1 */
    --tone-oxblood: #8B2635; /* 8.0:1 */
    /* Barn red, sampled from the NuCedar vertical-siding display board (Sunny, 2026-10-05). */
    --tone-barn: linear-gradient(160deg, #7A2E22 0%, #5A1C15 55%, #3A120D 100%); /* cream icon 8.7-15.3:1 */
    --tone-navy: #2E3A50;    /* 10.6:1 */
    --tone-sage: #5C6B4E;    /* 5.3:1 */
    --tone-bronze: #C19B5E;  /* NuCedar's highlight; cream would be 2.4:1, so its icon is dark ink (7.1:1) */

    /* ---- 4. Gold alphas (rules, edges, washes on green) ---- */
    --gold-line: rgba(201, 168, 76, .22);
    --gold-edge: rgba(201, 168, 76, .45);
    --gold-bar: linear-gradient(180deg, #D4B45C 0%, #C09A45 55%, #A88438 100%); /* table heads */
    --gold-bar-ink: #1A1408;
    --gold-hi: #E8D48A;
    --gold-bar-edge: #7A5F24;

    /* ---- 5. Surfaces and support colors ---- */
    --paper: #FFFFFF;
    --paper-tint: #FBFBF7;
    --paper-cream: #FBF7EC;  /* cream dialogs and cards */
    --paper-cream-2: #F1E8D2;
    --field: #F6EDD3;        /* a form field on green */
    --field-focus: #FFFDF6;
    --field-edge: rgba(201, 168, 76, .75);
    --placeholder: #7A7462;
    --pine: #13261C;
    --pine-3: #1B3326;
    --pine-deep: #08110C;
    --onyx: linear-gradient(160deg, #050505 0%, #141516 55%, #2A2C2E 100%);
    --onyx-solid: #141516;
    --text-soft: #5E6964;
    --success: #2D5F3F;
    --success-on-dark: #6FAF86;
    --danger-dp: #5F1820;
    --danger-on-dark: #E0707A;
    --warning-on-dark: #E0AE5C;
    --code: #8A3357;
    --table-stripe: #F6F1E4;
    --table-rule: #E6DDC8;
    --badge-ink: #08110C;

    /* Catalog colors for the Agility cards' icon chips (gardenstatelumber.com, 2026-10-01) */
    --mk-gold-a: #D9BC6A;    --mk-gold-b: #B08A3C;    --mk-gold-e: #6E5620;
    --mk-royal-a: #2A4C86;   --mk-royal-b: #172E57;   --mk-royal-e: #0D1B36;
    --mk-navy-a: #23405E;    --mk-navy-b: #13263B;    --mk-navy-e: #0A1624;
    --mk-crimson-a: #7A1F26; --mk-crimson-b: #46100F; --mk-crimson-e: #2A0909;
    --mk-slate-a: #34322F;   --mk-slate-b: #141312;   --mk-slate-e: #080807;
    --mk-taupe-a: #6E5E4C;   --mk-taupe-b: #3F352A;   --mk-taupe-e: #241E18;
    --mk-orange-a: #8E5426;  --mk-orange-b: #573014;  --mk-orange-e: #321A0A;
    --mk-letter: #E6CD85;



    /* ---- 9a. Alpha palette: the palette colors at set opacities (shadows, glows, edges, washes).
          Named --a-<color>-<percent>; components use these, never an rgba() of their own. ---- */
    --black: #000;
    --a-gold-10: rgba(201, 168, 76, .10);
    --a-gold-deep-14: rgba(176, 137, 53, .14);
    --a-ink-92: rgba(11, 20, 16, .92);
    --a-black-60: rgba(0, 0, 0, .6);
    --a-white-35: rgba(255, 255, 255, .35);
    --a-black-25: rgba(0, 0, 0, .25);
    --a-gold-16: rgba(201, 168, 76, .16);
    --a-gold-35: rgba(201, 168, 76, .35);
    --a-gold-8: rgba(201, 168, 76, .08);
    --a-gold-85: rgba(201, 168, 76, .85);
    --a-gold-dark-30: rgba(110, 86, 32, .30);
    --a-gold-deep-22: rgba(176, 137, 53, .22);
    --a-rule-55: rgba(190, 179, 155, .55);
    --a-white-5: rgba(255, 255, 255, .05);
    --a-black-15: rgba(0, 0, 0, .15);
    --a-black-20: rgba(0, 0, 0, .2);
    --a-black-35: rgba(0, 0, 0, .35);
    --a-black-45: rgba(0, 0, 0, .45);
    --a-black-8: rgba(0, 0, 0, .08);
    --a-black-soft-55: rgba(5, 5, 5, .55);
    --a-cream-35: rgba(250, 246, 236, .35);
    --a-cream-8: rgba(250, 246, 236, .08);
    --a-cream-85: rgba(250, 246, 236, .85);
    --a-gold-12: rgba(201, 168, 76, .12);
    --a-gold-14: rgba(201, 168, 76, .14);
    --a-gold-18: rgba(201, 168, 76, .18);
    --a-gold-30: rgba(201, 168, 76, .30);
    --a-gold-45: rgba(201, 168, 76, .45);
    --a-gold-50: rgba(201, 168, 76, .5);
    --a-gold-55: rgba(201, 168, 76, .55);
    --a-gold-75: rgba(201, 168, 76, .75);
    --a-gold-80: rgba(201, 168, 76, .8);
    --a-gold-deep-10: rgba(176, 137, 53, .10);
    --a-gold-deep-12: rgba(176, 137, 53, .12);
    --a-gold-deep-16: rgba(176, 137, 53, .16);
    --a-gold-deep-45: rgba(176, 137, 53, .45);
    --a-ink-text-10: rgba(26, 38, 32, .10);
    --a-ink-text-14: rgba(26, 38, 32, .14);
    --a-ink-text-6: rgba(26, 38, 32, .06);
    --a-ink-text-7: rgba(26, 38, 32, .07);
    --a-panel-hi-92: rgba(10, 13, 11, .92);
    --a-panel-lo-96: rgba(8, 11, 9, .96);
    --a-sheen-32: rgba(246, 249, 252, .32);
    --a-status-off-85: rgba(229, 72, 77, .85);
    --a-status-ok-85: rgba(46, 204, 113, .85);
    --a-tx-75: rgba(244, 238, 221, .75);
    --a-white-14: rgba(255, 255, 255, .14);
    --a-white-22: rgba(255, 255, 255, .22);
    --a-white-25: rgba(255, 255, 255, .25);
    --a-white-38: rgba(255, 255, 255, .38);
    --a-white-4: rgba(255, 255, 255, .04);
    --a-white-45: rgba(255, 255, 255, .45);
    --a-white-50: rgba(255, 255, 255, .5);
    --a-white-6: rgba(255, 255, 255, .06);
    --a-ink-35: rgba(11, 20, 16, .35);
    --a-ink-50: rgba(11, 20, 16, .5);
    --a-black-30: rgba(0, 0, 0, .3);
    --a-forest-22: rgba(45, 95, 63, .22);
    --a-rule-35: rgba(190, 179, 155, .35);


    /* -- 1b. Allan's alias names (orderform, pricesheets, 5thornton read these) -- */
    /* Aliases in the naming of Allan's GSL sites (orderform, pricesheets, 5thornton), so one tokens.css can
       serve a GSL site and the portal. Note: the portal's --text-soft (#5E6964) is darker than the sites'
       (#7A8580), which is 3.7:1 on cream and fails AA for body text. */
    --ink: var(--ink0);
    --ink-2: var(--ink1);
    --ink-3: var(--ink2);
    --ink-4: var(--ink3);
    --gold-br: var(--gold-b);
    --gold-dp: var(--gold-d);
    --cream-2: var(--cream2);
    --cream-3: var(--cream3);
    --cream-4: var(--cream4);
    --text-dark: var(--ltx);
    --text-mid: var(--ltx2);
    --text-on-dark: var(--tx);
    --text-on-dark-soft: var(--tx2);
    --rule-strong: var(--rule-s);


    /* -- 1c. Roles -- */
    /* Edges on cream surfaces (cream panels, tables, dialogs re-declare --gsl-border with these). */
    --cream-edge: #D4C9B0;
    --cream-edge-strong: #B5A889;
    /* ----
       ROLES - what each part of a screen uses. Components read ONLY these (and
       the size scale); change a role here to restyle that part everywhere.
       Every role is listed in DESIGN.md with the parts that use it.
       ---- */

    /* Frame: the page behind everything. The price sheets' ink ground: a gold glow top-left, a forest glow
       bottom-right, and a fine grain over both. */
    --frame-bg-from: var(--ink0);
    --frame-bg-mid: var(--ink1);
    --frame-bg-to: var(--ink0);
    --frame-glow: var(--a-forest-22);
    --frame-glow-gold: var(--a-gold-10);
    --frame-bg: radial-gradient(900px 500px at 15% -10%, var(--frame-glow-gold), transparent 60%),
                radial-gradient(800px 600px at 100% 100%, var(--frame-glow), transparent 60%),
                linear-gradient(180deg, var(--frame-bg-from) 0%, var(--frame-bg-mid) 40%, var(--frame-bg-to) 100%);
    --frame-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    --frame-grain-opacity: .16;
    /* The medallion, once, larger than the window and barely there, centered behind the page: a whisper in
       the ground behind the cards. It stays put while the page scrolls. */
    --frame-mark: url("../img/gsl-medallion.webp");
    --frame-mark-size: max(590px, min(105vw, 142vh));
    --frame-mark-opacity: .035;

    /* Header: the fixed bar with the GSL seal and name on the left, the account on the right. */
    --header-bg: linear-gradient(180deg, var(--ink0) 0%, var(--ink1) 60%, var(--ink2) 100%);
    --header-rule: linear-gradient(90deg, #A8883A 0%, #C5A55A 25%, #E8D48A 50%, #C5A55A 75%, #A8883A 100%);
    --header-height: 72px;
    --header-h: var(--header-height);
    --header-logo-height: 44px;              /* the seal's box; the artwork has a margin, so the seal reads at about 38px */
    --header-name-size: 21px;
    --header-control: var(--tx2);
    --header-control-border: var(--a-rule-35);
    --breadcrumb-bg: var(--ink1);

    /* Text. */
    --text-on-frame: var(--tx);
    --text-muted-on-frame: var(--tx2);
    --text-faint-on-frame: var(--tx3);
    --text-on-card: var(--ltx);
    --text-muted-on-card: var(--ltx2);
    --heading-on-frame: var(--cream);
    --heading-accent: var(--gold-b);         /* the italic word in a page title */

    /* Card: the dashboard's app and portal-page tiles (the price sheets' hub tile): flat cream on the ink
       ground, a gold shimmer edge along the top, the art above the words. */
    --card-bg: var(--cream);
    --card-border: var(--gold-b);
    --card-radius: 12px;
    --card-shadow: 0 0 0 1px var(--card-ring), 0 0 14px var(--card-glow), 0 12px 40px var(--a-ink-35), 0 2px 8px var(--a-black-25);
    --card-shadow-hover: 0 0 0 1px var(--card-ring-hover), 0 0 22px var(--card-glow-hover), 0 28px 80px var(--a-ink-50), 0 4px 12px var(--a-black-30);
    --card-lift: -4px;                       /* how far the favorite mark and grip rise with a hovered tile */
    --card-grow: 1.035;                      /* how much a tile grows under the pointer, or under a finger */
    --card-edge: none;                       /* the gold bar along a tile's top: gone since 1.4.8 (Allan, 2026-10-29) */
    --card-edge-height: 0px;
    --card-ring: var(--a-gold-50);           /* the tight glowing border on every tile */
    --card-glow: var(--a-gold-30);
    --card-ring-hover: var(--a-gold-75);
    --card-glow-hover: var(--a-gold-50);
    --card-padding: 18px 24px 24px;
    --card-foot-tint: 55%;                   /* how much of the category colour reaches the card's bottom edge */
    --card-body-top: #1E1B14;                /* the name's ground: a warm near-black at the top ... */
    --card-body-mid: #0A0906;                /* ... black through the middle ... */
    --card-body-bg: var(--black);            /* ... easing into the category's colour (--tag, set on the section) at the bottom; the gradient is written on .app-tile-body, where --tag is known (Allan, 2026-10-29) */
    --card-body-rule: var(--a-gold-30);                                                  /* the hairline between art and name */
    --card-title-color: var(--cream);
    --card-title-size: 1.375rem;
    /* Card art: the picture area above the words. An uploaded image sits on it as it was made; a logo that
       only exists in white, or on its own dark ground, gets the dark ground; a tool without an image shows
       its line icon, or its initials. */
    --card-art-height: 150px;
    --card-art-bg: #EFE7D2;
    --card-art-bg-dark: var(--ink1);
    --card-art-image-max: 72%;               /* of the art area, each way */
    --card-art-icon: var(--gold-d);
    --card-art-icon-size: 64px;              /* GSL's drawn icons */
    --card-art-glyph-size: 52px;             /* Bootstrap's glyphs fill more of their box */
    --card-art-icon-stroke: 1.15;
    --tile-min-width: 250px;                 /* the narrowest a tile may get before the grid drops a column */
    --tile-gap: 22px;
    /* Favorite mark: the GSL seal in a tile's top corner. Idle it is the one-color gold seal, faint; chosen,
       it is the medallion in full color. */
    --fav-mark: var(--frame-mark);
    --fav-mark-idle: url("../img/gsl-seal-gold.webp");
    --fav-size: 26px;
    --fav-inset: 11px;                       /* from the tile's corner to the seal; the 40px touch area reaches inward */
    --fav-idle-opacity: .4;
    --fav-hover-opacity: .65;
    /* Favorites only: the black plate beside the lede, holding an upright switch (up is on). */
    --fav-toggle-height: 48px;
    --fav-toggle-bg: linear-gradient(180deg, #E8D48A 0%, #C9A84C 55%, #A8883A 100%);   /* the shiny gold plate */
    --fav-toggle-bg-on: linear-gradient(180deg, #F3E4A6 0%, #D8B95C 55%, #B8944A 100%);
    --fav-toggle-border: var(--gold-d);
    --fav-toggle-border-on: var(--cream);
    --fav-toggle-text: var(--ink0);
    --fav-toggle-glow-on: 0 0 0 1px var(--a-gold-75), 0 0 18px var(--a-gold-50);
    --fav-toggle-seal-off: grayscale(1) brightness(.25);                               /* the seal, blacked out while off */
    --fav-toggle-seal-on: drop-shadow(0 0 6px var(--cream));                            /* and lit while on */
    --fav-switch-width: 18px;
    --fav-switch-height: 32px;
    --fav-switch-track: rgba(0, 0, 0, .28);
    --fav-switch-track-on: var(--ink0);
    --fav-switch-knob: rgba(0, 0, 0, .55);
    --fav-switch-knob-on: var(--gold-b);
    /* A category on the dashboard: serif heading, then a thin gold rule out to the edge. */
    --category-gap: var(--sp-7);
    --category-title-size: 1.5rem;
    --category-rule-drop: 2px;
    --category-bar-width: 100%;              /* the category's colour bar under its name: the full width of the name (Allan, 2026-10-29) */
    --category-bar-height: 3px;
    --category-bar-gap: 7px;               /* the rule sits this far under the heading's middle line, level with the middle of its letters */

    /* The admin board (Settings -> Apps): the pool and the category cards, holding the apps as small tiles. */
    --board-tile-width: 8.75rem;             /* a tile on the board, switch and edit button under it */
    --board-gap: 14px;
    --board-card-bg: var(--a-black-30);      /* a category card's ground on the frame */
    --board-card-border: var(--a-gold-30);
    --board-card-radius: var(--card-radius);
    --board-bar-height: 3px;                 /* the category's colour along the bottom of its heading */
    --board-drop-ring: var(--a-gold-50);     /* the zones light up while a tile is in the air */
    /* The colour control (the category sheet): sixteen preset swatches in two rows of eight, and a picker. */
    --swatch-height: 44px;
    --swatch-radius: 6px;
    --swatch-gap: 6px;
    --swatch-ring-on: var(--ink0);              /* the chosen swatch's ring, on the sheet's paper */

    /* Medallion: an app's icon on a disc (Settings -> Apps). A row's icon_color sets --medallion-bg. */
    --medallion-size: 58px;
    --medallion-icon-size: 26px;
    --medallion-custom-icon-size: 32px;      /* GSL's drawn icons fill less of their box than Bootstrap's glyphs */
    --medallion-bg: var(--gold-tint);
    --medallion-icon: var(--ltx);
    --medallion-ring: 0 0 0 1.5px var(--gold-b);
    --medallion-icon-on-tone: var(--cream);

    /* Metal controls: the back button, tab counts, the Select pill (shiny gold). */
    --control-metal-from: var(--gold-hi);
    --control-metal-mid: #D9B85A;
    --control-metal-to: #A8883A;
    --control-metal-bg: linear-gradient(135deg, var(--control-metal-from) 0%, var(--control-metal-mid) 45%, var(--GOLD) 70%, var(--control-metal-to) 100%);
    --control-metal-border: #8A6B28;
    --control-metal-text: #1A1408;

    /* Button, primary: the price sheets' gold button. */
    --btn-primary-from: #D9B85A;
    --btn-primary-to: #B08935;
    --btn-primary-bg: linear-gradient(180deg, var(--btn-primary-from), var(--btn-primary-to));
    --btn-primary-border: #8A6B28;
    --btn-primary-text: #1A1408;
    /* Button, quiet: gold outline on the frame. */
    --btn-quiet-bg: var(--a-gold-8);
    --btn-quiet-bg-hover: var(--a-gold-16);
    --btn-quiet-border: var(--a-gold-45);
    --btn-quiet-text: var(--gold-b);

    /* Table: the price sheets' parchment grid. */
    --table-head-from: #D9B85A;
    --table-head-to: #B08935;
    --table-head-bg: linear-gradient(180deg, var(--table-head-from), var(--table-head-to));
    --table-head-text: #1A1408;
    --table-group-bg: linear-gradient(180deg, #242424 0%, #0A0A0A 55%, #000 100%); /* column-group band */
    --table-group-text: var(--gold-b);
    --table-group-border: var(--a-gold-85);
    --table-row-odd: #F6F0E0;
    --table-row-even: #ECE4CD;
    --table-row-hover: var(--gold-tint-2);
    --table-cell-text: var(--ltx);
    --table-cell-rule: var(--a-rule-55);
    --table-group-rule: var(--a-gold-dark-30);
    --table-key-text: var(--gold-d);         /* the key column (SKU-style) */
    --table-sub-text: var(--ltx2);           /* the gray line under a key */
    --table-text-max-width: 22rem;           /* a text cell longer than this ends in ... (full value on hover) */

    /* Form fields. On cream (tables, dialogs) and on the dark frame (toolbars, dark panels). */
    --field-bg-on-cream: #FFFDF6;
    --field-border-on-cream: #9C8753;
    --field-text-on-cream: var(--ltx);
    --field-focus-glow-on-cream: var(--a-gold-deep-22);
    --field-bg-on-dark: var(--a-white-5);
    --field-border-on-dark: var(--a-gold-45);
    --field-text-on-dark: var(--cream);
    --field-focus-glow-on-dark: var(--a-gold-12);
    --select-caret-on-dark: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23C9A84C' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
    --select-caret-on-cream: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%231A2620' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");

    /* Toolbar: the dark-green bar with a gold rule (filters, search). */
    --toolbar-bg: linear-gradient(180deg, var(--ink2), var(--ink0));
    --toolbar-rule: var(--gold-b);
    --toolbar-label: var(--tx2);

    /* Highlight: gold (eyebrow tails, thin rules, the page-title icon). */
    --highlight-accent: var(--gold-b);
    --highlight-text-on-frame: var(--gold-b);
    --highlight-rule: var(--a-gold-30);
    --highlight-icon-bg: var(--control-metal-bg);
    --highlight-icon-border: var(--control-metal-border);
    --highlight-icon-text: var(--control-metal-text);

    /* Sign-in page. */
    /* The photo's overlay: nucedar-quote's warm dark vignette, not a green tint (Sunny, 2026-10-05:
       "instead of the green darkish tint"). Dark behind the seal and button, fading toward the edges. */
    --signin-overlay-rgb: 20, 15, 8;
    --signin-overlay: radial-gradient(ellipse 62% 78% at 50% 42%, rgba(var(--signin-overlay-rgb), .86) 0%, rgba(var(--signin-overlay-rgb), .70) 45%, rgba(var(--signin-overlay-rgb), .34) 75%, rgba(var(--signin-overlay-rgb), .12) 100%),
                      linear-gradient(180deg, rgba(var(--signin-overlay-rgb), .30) 0%, rgba(var(--signin-overlay-rgb), .05) 35%, rgba(var(--signin-overlay-rgb), .45) 100%);
    --signin-overlay-phone: linear-gradient(180deg, rgba(var(--signin-overlay-rgb), .25) 0%, rgba(var(--signin-overlay-rgb), .6) 40%, rgba(var(--signin-overlay-rgb), .92) 100%);
    --signin-photo-fallback: #2A2520;        /* behind the photo while it loads */
    --signin-content-width: 340px;
    --signin-wordmark-size: 30px;
    --signin-foot-rule: var(--a-gold-30);
    --signin-error-text: #FFD9D3;
    /* Text over the photo, brighter and lifted by a soft dark shadow (Sunny, 2026-10-05: "whiter ...
       shadow just so that it will be easier to see it"). */
    --signin-text: #FBF8F1;                  /* "Garden State": near-white */
    --signin-accent: #DCC06E;                /* "Lumber": the gold, one step lighter */
    --signin-eyebrow: #F3E3D2;               /* "EMPLOYEE PORTAL": warm cream with a hint of copper */
    --signin-foot-text: var(--a-cream-85);   /* the footer line */
    --signin-text-shadow: 0 1px 2px var(--a-black-60), 0 2px 12px var(--a-black-45);
    --signin-seal-size: 132px;
    --signin-seal-glow: drop-shadow(0 0 22px var(--a-gold-35)) drop-shadow(0 10px 18px var(--a-black-60));
    --signin-button-bg: linear-gradient(180deg, var(--gold-hi), var(--control-metal-mid) 50%, var(--GOLD));
    --signin-button-shadow: 0 1px 0 var(--a-white-35) inset, 0 4px 12px var(--a-black-25);

    /* Status. */
    --status-ok: #2ECC71;
    --status-off: #E5484D;
    --status-ok-glow: var(--a-status-ok-85);
    --status-off-glow: var(--a-status-off-85);

    /* Focus + the select-to-refer inspector. */
    --focus-ring: var(--gold-b);
    --inspector-outline: var(--gold-b);
    --inspector-pinned: var(--gold-hi);
    --inspector-panel-bg: var(--a-ink-92);    /* dark ink glass: reads over the green frame and the cream cards */
    --inspector-card-width: min(24rem, calc(100vw - 32px));
    --inspector-edge: 16px;                  /* the pill's distance from the corner */
    --inspector-pill-width: 11.5rem;
    --inspector-panel-border: var(--gold-b);
    --inspector-panel-text: var(--tx);

    /* ---- 7. Bootstrap-facing roles (what portal.css reads for surfaces) ---- */
    --gsl-body: var(--ink1);
    --gsl-body-2: var(--pine-deep);
    --gsl-surface: var(--pine);
    --gsl-surface-2: var(--pine-3);
    --gsl-surface-hover: var(--pine-3);
    --gsl-txt: var(--tx);
    --gsl-txt-muted: var(--tx2);
    --gsl-txt-soft: var(--tx3);
    --gsl-heading: var(--cream);
    --gsl-border: rgba(201, 168, 76, .26);
    --gsl-border-soft: rgba(201, 168, 76, .14);
    --gsl-border-strong: rgba(201, 168, 76, .55);
    --gsl-gold: var(--gold-b);
    --gsl-gold-br: #DCC06E;
    --gsl-gold-dp: var(--gold-b);
    --gsl-gold-soft: rgba(201, 168, 76, .45);
    --gsl-gold-faint: rgba(201, 168, 76, .14);
    --gsl-accent: var(--gold-b);
    --gsl-danger: var(--danger-on-dark);
    --gsl-card-bg: linear-gradient(180deg, rgba(31, 63, 44, .55) 0%, rgba(13, 27, 19, .85) 100%);
    --gsl-card-shadow: 0 1px 0 rgba(255, 255, 255, .05) inset, 0 8px 22px rgba(0, 0, 0, .35);
    --gsl-card-shadow-hover: 0 1px 0 rgba(255, 255, 255, .06) inset, 0 20px 44px rgba(0, 0, 0, .5);

    /* ---- 8. Bootstrap mapping ---- */
    --bs-primary: var(--gsl-gold);
    --bs-primary-rgb: 201, 168, 76;
    --bs-success: var(--success-on-dark);
    --bs-success-rgb: 111, 175, 134;
    --bs-danger: var(--gsl-danger);
    --bs-danger-rgb: 224, 112, 122;
    --bs-warning: var(--warning-on-dark);
    --bs-warning-rgb: 224, 174, 92;
    --bs-info: #9CBFDE;
    --bs-info-rgb: 156, 191, 222;
    --bs-emphasis-color: var(--cream);
    --bs-emphasis-color-rgb: 250, 246, 236;
    --bs-link-color: var(--gsl-gold-br);
    --bs-link-color-rgb: 220, 192, 110;
    --bs-link-hover-color: var(--cream);
    --bs-link-hover-color-rgb: 250, 246, 236;
    --bs-body-bg: var(--gsl-body);
    --bs-body-color: var(--gsl-txt);
    --bs-heading-color: var(--gsl-heading);
    --bs-border-color: var(--gsl-border);
    --bs-border-color-translucent: var(--gsl-border-soft);
    --bs-secondary-color: var(--gsl-txt-muted);
    --bs-secondary-bg: var(--gsl-surface-2);
    --bs-tertiary-bg: var(--gsl-body-2);
    --bs-danger-text-emphasis: #F2A7AE;
    --bs-success-text-emphasis: #A9D6B8;
    --bs-warning-text-emphasis: #F0CC8A;
    --bs-code-color: #E8A6C4;

    /* The onyx door and its gold lettering (Agility/Transfers buttons and the "live site" dialog). */
    --ink-door: var(--onyx);
    --ink-gold: var(--gold-b);
    --ink-gold-hi: var(--gold-hi);

    /* -- 1d. Size scale and type -- */
    /* ---- 9b. Sizes: spacing scale, radii, depth, page frame ---- */
    --r-sm: 3px;
    --r-md: 4px;
    --r-lg: 6px;
    --r-xl: 8px;
    --sh-3: 0 12px 40px var(--a-ink-text-10), 0 2px 8px var(--a-ink-text-6);
    --sp-1: 4px;
    --sp-2: 8px;
    --sp-3: 12px;
    --sp-4: 16px;
    --sp-5: 24px;
    --sp-6: 32px;
    --sp-7: 48px;
    --page-max: 1200px;
    --page-gutter: var(--sp-6);

    /* ---- 9. Type ---- */
    --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --serif: "Source Serif 4", Georgia, "Times New Roman", serif;
    --mono: "JetBrains Mono", "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* == 2. Base == */
/* The page itself: body, type, focus, text helpers, and the cream surfaces that re-declare text roles. */

/* -- Page, type and focus -- */
/* GSL Portal - components, layered over Bootstrap 5 (CDN, no build step).

   ONE theme: the price sheets' ink ground with cream cards and gold accents. There is no light/dark switch; <html> carries a
   fixed data-bs-theme="dark" so Bootstrap's own components start dark.

   ---- WHAT TO EDIT ----
   Colors live in tokens.css (loaded before this file) and nowhere else: this
   file reads var(--...) only. Spacing, radii and the page width are below.

   Fonts (Google Fonts <link> in the page head):
     * Inter            - body / UI
     * Source Serif 4   - display headings and card titles
     * JetBrains Mono   - micro-labels, tags, monospace/data */
/* Keyboard focus: one visible gold ring everywhere (on green and on cream). */
:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}
body {
    min-height: 100vh;
    font-family: var(--sans);
    font-size: 14px;
    line-height: 1.55;
    background-color: var(--gsl-body);
    background-image: var(--frame-bg);
    background-attachment: fixed;
    color: var(--gsl-txt);
    padding-top: var(--header-h);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}
/* The grain: a fine paper noise over the ground, behind everything on the page. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-image: var(--frame-grain);
    opacity: var(--frame-grain-opacity);
    mix-blend-mode: soft-light;
}
/* The watermark: the medallion under the grain, centered in the window below the header. Not on the
   sign-in screen. */
body::after {
    content: "";
    position: fixed;
    inset: var(--header-h) 0 0 0;
    z-index: -2;
    pointer-events: none;
    background: var(--frame-mark) no-repeat center / var(--frame-mark-size) auto;
    opacity: var(--frame-mark-opacity);
}
body.signin-open::after { display: none; }
h1, h2, h3, h4, h5, h6 { font-family: var(--serif); }

/* -- Text helpers -- */
.section-label {
    font-family: var(--mono);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--gsl-accent);
}
.muted-text {
    color: var(--gsl-txt-soft);
}
.text-secondary {
    color: var(--gsl-txt-muted) !important;
}
.border-secondary {
    border-color: var(--gsl-border) !important;
}

/* -- Surfaces: cream panels re-declare the roles for dark text -- */
/* Cream surfaces (tables, the panels around them, cream cards, dialogs) re-declare the roles for dark
   text on cream. */
.on-cream,
.panel:has(> .table),
.panel:has(> .overflow-auto > .table),
.panel:has(> .table-responsive > .table),
.table,
.import-card.ic,
.file-card,
.modal-content {
    color-scheme: light;
    --gsl-surface: var(--paper);
    --gsl-surface-2: var(--paper-tint);
    --gsl-surface-hover: var(--cream2);
    --gsl-txt: var(--ltx);
    --gsl-txt-muted: var(--ltx2);
    --gsl-txt-soft: var(--text-soft);
    --gsl-heading: var(--ink0);
    --gsl-border: var(--cream-edge);
    --gsl-border-strong: var(--cream-edge-strong);
    --gsl-accent: var(--gold-d);
    --gsl-gold: var(--gold);
    --gsl-gold-faint: var(--a-gold-deep-14);
    --gsl-danger: var(--danger);
    --bs-body-color: var(--ltx);
    --bs-body-bg: var(--paper);
    --bs-border-color: var(--cream-edge);
    --bs-secondary-color: var(--ltx2);
    --bs-emphasis-color: var(--ink0);
    --bs-code-color: var(--code);
    --bs-link-color: var(--forest);
    --bs-link-hover-color: var(--gold-d);
    --bs-danger: var(--danger);
    --bs-danger-rgb: 139, 38, 53;
    --bs-danger-text-emphasis: var(--danger-dp);
}

/* == 3. Layout and frame == */
/* The fixed header, the breadcrumb, the page shell and title band, and the breakpoints. */

/* -- Header -- */
/* The price sheets' header: the seal and "Garden State Lumber" on the left, the account on the right. */
#app-header {
    background: var(--header-bg);
    padding: 0 var(--page-gutter);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    height: var(--header-h);
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 101;
    font-size: 16px;
    color: var(--text-on-frame);
}
/* The gold rule under the header (from the client's own apps). */
#app-header::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 2px;
    background: var(--header-rule);
}
#app-header .brand {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    min-width: 0;
    margin-left: -3px;                       /* the seal's own margin: its edge lines up with the page */
    border-radius: var(--r-md);
    color: var(--text-on-frame);
    text-decoration: none;
}
#app-header .brand img {
    width: var(--header-logo-height);
    height: var(--header-logo-height);
    flex: none;
}
#app-header .brand-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    font-family: var(--serif);
    font-size: var(--header-name-size);
    font-weight: 600;
    letter-spacing: .01em;
    white-space: nowrap;
}
#app-header .brand-name i { color: var(--heading-accent); }
#app-header .actions {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
}
#portal-account { display: inline-flex; align-items: center; gap: 14px; min-width: 0; }
.account-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 12.5px;
    color: var(--header-control);
}
/* The one account control: the price sheets' ghost button, 44px tap target. */
.account-btn {
    flex: none;
    min-height: 44px;
    padding: 0 16px;
    border: 1px solid var(--header-control-border);
    border-radius: var(--r-lg);
    background: transparent;
    color: var(--header-control);
    font: 500 12.5px var(--sans);
    white-space: nowrap;
    cursor: pointer;
    transition: color .15s ease, border-color .15s ease;
}
.account-btn:hover { color: var(--text-on-frame); border-color: var(--gold-edge); }
.portal-preview-chip { min-width: 0; }
/* Narrow screens: the name gives its room to the brand. */
@media (max-width: 767.98px) {
    .account-name { display: none; }
}
/* The version pill sits between the name and Sign out (the price sheets' header). */
#portal-account .gsl-status { flex: none; }
/* Phones: the header row is full (seal, name, Sign out), so the version tucks under the name as a
   second line of the lockup, without its frame. The header is the positioned box it hangs from. */
@media (max-width: 575.98px) {
    #app-header .brand-name { padding-bottom: 14px; }
    #portal-account .gsl-status {
        position: absolute;
        left: calc(var(--page-gutter) + var(--header-logo-height) + 6px);
        top: calc(50% + 3px);
        padding: 0;
        border: 0;
        font-size: .6rem;
        pointer-events: none;
    }
}
@media (max-width: 575.98px) {
    :root { --header-name-size: clamp(13px, 3.7vw, 17px); }   /* "Garden State Lumber Apps" on one line down to 360px */
}
/* A small chip in the header's actions: takes no page space and can be closed. */
.portal-preview-chip {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .2rem .35rem .2rem .6rem;
    border-radius: 999px;
    border: 1px solid var(--a-gold-45);
    color: var(--gold-b);
    font-family: var(--mono);
    font-size: .64rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    white-space: nowrap;
}
.portal-preview-chip a { color: var(--cream); }
.portal-preview-chip button {
    border: 0;
    background: none;
    color: inherit;
    padding: 0 .15rem;
    line-height: 1;
    cursor: pointer;
}

/* -- Breadcrumb -- */
/* The breadcrumb bar under the header on every page but the dashboard (the price sheets' back bar):
   "<- Dashboard - <Page>". */
.crumb {
    background: var(--breadcrumb-bg);
    border-bottom: 1px solid var(--gold-line);
}
.crumb-inner {
    max-width: calc(var(--page-max) + 2 * var(--page-gutter));
    margin: 0 auto;
    padding: 10px var(--page-gutter);
    display: flex;
    align-items: center;
    gap: 14px;
}
.crumb-back {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: 7px 14px;
    border-radius: var(--r-lg);
    border: 1px solid var(--control-metal-border);
    background: var(--control-metal-bg);
    color: var(--control-metal-text);
    font: 600 10.5px var(--mono);
    letter-spacing: .18em;
    text-transform: uppercase;
    text-decoration: none;
    box-shadow: 0 1px 0 var(--a-white-25) inset, 0 2px 8px var(--a-black-35);
    transition: transform .15s ease, filter .15s ease;
}
.crumb-back:hover { color: var(--control-metal-text); filter: brightness(1.06); transform: translateY(-.5px); }
.crumb-trail {
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--text-muted-on-frame);
}
.crumb-trail::before { content: "\00B7"; margin-right: 14px; color: var(--text-faint-on-frame); }
.crumb-trail b { color: var(--gold-b); font-weight: 600; }
.crumb-back { min-height: 36px; white-space: nowrap; }
.crumb-trail { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 575.98px) {
    .crumb-inner { gap: 10px; }
    .crumb-back { min-height: 44px; }
    .crumb-trail::before { margin-right: 10px; }
}

/* -- Page shell: frame and title band -- */
/* Every portal page wraps its content in <main class="container-xxl ...">; the frame is
   set here once so each page gets the same width and gutters without editing its markup. */
body > main.container-xxl {
    max-width: calc(var(--page-max) + 2 * var(--page-gutter));
    padding: var(--sp-6) var(--page-gutter) var(--sp-7) !important;
}
body > main.container-xxl { padding-top: var(--sp-5) !important; }
.page-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sp-3);
    padding: 0 0 var(--sp-4);
    margin-bottom: var(--sp-5) !important;
    background: transparent;
    border: 0;
    border-bottom: 1px solid var(--highlight-rule);
    border-radius: 0 !important;
    box-shadow: none;
}
.page-toolbar h1 {
    margin: 0;
    font-size: clamp(1.75rem, 3.4vw, 2.125rem);
    font-weight: 600;
    line-height: 1.1;
    color: var(--heading-on-frame);
}
.page-toolbar h1 em {
    font-style: italic;
    color: var(--heading-accent);
}
.page-eyebrow {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    flex-basis: 100%;
    font-family: var(--mono);
    font-size: .625rem;
    font-weight: 600;
    letter-spacing: .24em;
    text-transform: uppercase;
    color: var(--gsl-accent);
    margin-bottom: calc(-1 * var(--sp-2));
}
.page-eyebrow::after {
    content: "";
    width: 60px;
    height: 1px;
    background: var(--highlight-accent);
    opacity: .4;
}
/* The line under a page title that says what the page holds: its own row, the words kept to 60 characters. */
.page-lede {
    flex: 0 0 100%;
    margin: calc(-1 * var(--sp-1)) 0 0;
    padding-right: max(0px, calc(100% - 60ch));
    color: var(--text-muted-on-frame);
}

/* -- Breakpoints: role values that change with the screen width -- */
/* Phones: tighter gutter, shorter header. */
@media (max-width: 575.98px) {
    :root { --page-gutter: var(--sp-4); --header-h: 72px; }
}
/* Phones (below 576): the dashboard's tiles sit two to a row, with smaller art and titles. */
@media (max-width: 575.98px) {
    :root {
        --tile-gap: 14px;
        --card-padding: 14px 16px 18px;
        --card-title-size: 1.0625rem;
        --card-art-height: 104px;
        --card-art-icon-size: 46px;
        --card-art-glyph-size: 38px;
        --fav-size: 20px;
        --fav-inset: 6px;
        --category-gap: var(--sp-6);
        --category-title-size: 1.3rem;
    }
}

/* == 4. Components == */
/* Reusable parts, each reading roles only: buttons, badges, icons, panels, tiles, tables, toolbars, forms, off-canvas, tabs, toasts, dialogs. */

/* -- Buttons -- */
.btn-primary {
    --bs-btn-bg: var(--gsl-gold);
    --bs-btn-border-color: var(--gsl-gold);
    --bs-btn-hover-bg: var(--gsl-gold-br);
    --bs-btn-hover-border-color: var(--gsl-gold-br);
    --bs-btn-active-bg: var(--gsl-gold-br);
    --bs-btn-active-border-color: var(--gsl-gold-dp);
    --bs-btn-disabled-bg: var(--gsl-gold);
    --bs-btn-disabled-border-color: var(--gsl-gold);
}
.btn-outline-primary {
    --bs-btn-color: var(--gsl-accent);
    --bs-btn-border-color: var(--gsl-gold-soft);
    --bs-btn-hover-color: var(--gsl-accent);
    --bs-btn-hover-bg: var(--gsl-gold-faint);
    --bs-btn-hover-border-color: var(--gsl-gold);
    --bs-btn-active-color: var(--gsl-accent);
    --bs-btn-disabled-color: var(--gsl-txt-soft);
    --bs-btn-disabled-bg: transparent;
    --bs-btn-disabled-border-color: var(--gsl-border);
    --bs-btn-active-bg: var(--gsl-gold-faint);
    --bs-btn-active-border-color: var(--gsl-gold);
}
/* Segmented toggles (a btn-group of two or three choices): dark track, the active choice filled gold. */
main .btn-group {
    padding: 3px;
    gap: 2px;
    border-radius: var(--r-lg);
    background: var(--ink0);
    border: 1px solid var(--a-gold-45);
}
main .btn-group > .btn {
    --bs-btn-color: var(--a-tx-75);
    --bs-btn-bg: transparent;
    --bs-btn-border-color: transparent;
    --bs-btn-hover-color: var(--cream);
    --bs-btn-hover-bg: var(--a-gold-12);
    --bs-btn-hover-border-color: transparent;
    --bs-btn-active-color: var(--ink0);
    --bs-btn-active-bg: var(--gold-b);
    --bs-btn-active-border-color: transparent;
    border-radius: var(--r-md) !important;
    font-family: var(--mono);
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .18em;
    text-transform: uppercase;
}
main .btn-group > .btn.active {
    background: var(--ink-door);
    color: var(--ink-gold);
}
.btn-secondary {
    --bs-btn-hover-border-color: var(--gsl-gold-soft);
    --bs-btn-active-color: var(--gsl-heading);
    --bs-btn-active-bg: var(--gsl-surface-hover);
    --bs-btn-active-border-color: var(--gsl-gold);
}
.btn-outline-secondary {
    --bs-btn-color: var(--gsl-txt-muted);
    --bs-btn-border-color: var(--gsl-border-strong);
    --bs-btn-hover-color: var(--gsl-heading);
    --bs-btn-hover-bg: var(--gsl-surface-hover);
    --bs-btn-hover-border-color: var(--gsl-gold-soft);
    --bs-btn-active-color: var(--gsl-heading);
    --bs-btn-active-bg: var(--gsl-surface-hover);
    --bs-btn-active-border-color: var(--gsl-gold);
}
.btn-secondary {
    --bs-btn-color: var(--cream);
    --bs-btn-bg: transparent;
    --bs-btn-border-color: var(--a-gold-45);
    --bs-btn-hover-color: var(--cream);
    --bs-btn-hover-bg: var(--a-gold-12);
}
.gsl-btn-primary,
.btn-primary,
.gsl-btn {
    font-family: var(--mono);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    border-radius: var(--r-md);
}
.gsl-btn-primary,
.btn-primary {
    --bs-btn-color: var(--btn-primary-text);
    --bs-btn-hover-color: var(--btn-primary-text);
    --bs-btn-active-color: var(--btn-primary-text);
    --bs-btn-disabled-color: var(--btn-primary-text);
    background: var(--btn-primary-bg) !important;
    border: 1px solid var(--btn-primary-border) !important;
    color: var(--btn-primary-text) !important;
    box-shadow: 0 1px 0 var(--a-white-25) inset, 0 2px 8px var(--a-black-35);
}
.gsl-btn-primary:hover,
.btn-primary:hover { filter: brightness(1.06); transform: translateY(-.5px); }
.gsl-btn {
    background: var(--btn-quiet-bg);
    border: 1px solid var(--btn-quiet-border);
    color: var(--btn-quiet-text);
}
.gsl-btn:hover { background: var(--btn-quiet-bg-hover); color: var(--btn-quiet-text); }

/* -- Badges -- */
.badge-ghost {
    background: var(--gsl-gold-faint);
    color: var(--gsl-txt-muted);
}
.text-bg-success { background-color: var(--success-on-dark) !important; color: var(--badge-ink) !important; }
.text-bg-danger  { background-color: var(--danger-on-dark) !important; color: var(--badge-ink) !important; }
.text-bg-warning { background-color: var(--warning-on-dark) !important; color: var(--badge-ink) !important; }
.badge-available   { background-color: var(--success-on-dark); color: var(--badge-ink); }
.badge-unavailable { background-color: var(--danger-on-dark); color: var(--badge-ink); }

/* A category badge in its own color, so the same heading is recognized at a glance
   wherever it appears. The color comes from the palette the app form offers; a
   category with no color keeps the quiet gold badge above. */
.badge-tag { background: var(--tag); color: var(--tag-ink, var(--medallion-icon-on-tone)); }

/* The same color against a dashboard heading. */
.app-group-dot { display: none; }   /* replaced by the bar under the heading (1.5.1) */

/* -- Icons and icon chips -- */
/* 1. Black-and-gold "ink" for what you act on or read first: table headings, main buttons, the
      active tab, and Agility's headline numbers (like the dashboard's page tiles).
   2. Color in small doses, through icon chips, from gardenstatelumber.com's catalog colors
      (gold, Metro blue, Estate burgundy, warm copper): each screen has a door color (set by portal.js as
      <body data-screen="...">) for its title icon, and cards cycle the door colors. No green: the
      header and drawer already carry it (Sunny, 2026-10-01). Same in both themes. */
:root,
[data-screen] { --scr-a: var(--mk-gold-a); --scr-b: var(--mk-gold-b); --scr-edge: var(--mk-gold-e); --scr-ink: var(--gold-bar-ink); }
[data-screen="agility-imports"] { --scr-a: var(--mk-royal-a); --scr-b: var(--mk-royal-b); --scr-edge: var(--mk-royal-e); --scr-ink: var(--mk-letter); }
[data-screen="transfers"]       { --scr-a: var(--mk-orange-a); --scr-b: var(--mk-orange-b); --scr-edge: var(--mk-orange-e); --scr-ink: var(--mk-letter); }
[data-screen="settings"]        { --scr-a: var(--mk-crimson-a); --scr-b: var(--mk-crimson-b); --scr-edge: var(--mk-crimson-e); --scr-ink: var(--mk-letter); }
/* Re-declared wherever data-screen is set: a custom property resolves its var()s where it is declared. */
:root,
[data-screen] { --scr-door: linear-gradient(180deg, var(--scr-a) 0%, var(--scr-b) 100%); }
/* Icon chips */
.icon-chip {
    display: inline-grid;
    place-items: center;
    flex: none;
    width: 2.1rem;
    height: 2.1rem;
    border-radius: var(--r-md);
    background: var(--scr-door);
    color: var(--scr-ink);
    border: 1px solid var(--scr-edge);
    box-shadow: inset 0 1px 0 var(--a-white-22), 0 2px 6px var(--a-black-15);
    font-size: 1rem;
    line-height: 1;
}
.icon-chip-lg { width: 2.75rem; height: 2.75rem; font-size: 1.3rem; border-radius: var(--r-lg); }
.icon-chip.chip-gold    { --scr-a: var(--mk-gold-a);    --scr-b: var(--mk-gold-b);    --scr-edge: var(--mk-gold-e);    --scr-ink: var(--gold-bar-ink); }
.icon-chip.chip-blue    { --scr-a: var(--mk-royal-a);   --scr-b: var(--mk-royal-b);   --scr-edge: var(--mk-royal-e);   --scr-ink: var(--mk-letter); }
.icon-chip.chip-crimson { --scr-a: var(--mk-crimson-a); --scr-b: var(--mk-crimson-b); --scr-edge: var(--mk-crimson-e); --scr-ink: var(--mk-letter); }
.icon-chip.chip-navy    { --scr-a: var(--mk-navy-a);    --scr-b: var(--mk-navy-b);    --scr-edge: var(--mk-navy-e);    --scr-ink: var(--mk-letter); }
.icon-chip.chip-slate   { --scr-a: var(--mk-slate-a);   --scr-b: var(--mk-slate-b);   --scr-edge: var(--mk-slate-e);   --scr-ink: var(--mk-letter); }
.icon-chip.chip-orange  { --scr-a: var(--mk-orange-a);  --scr-b: var(--mk-orange-b);  --scr-edge: var(--mk-orange-e);  --scr-ink: var(--mk-letter); }
.icon-chip.chip-taupe   { --scr-a: var(--mk-taupe-a);   --scr-b: var(--mk-taupe-b);   --scr-edge: var(--mk-taupe-e);   --scr-ink: var(--mk-letter); }
.icon-chip[class*="chip-"] { background: linear-gradient(180deg, var(--scr-a) 0%, var(--scr-b) 100%); }
.page-toolbar .icon-chip-lg { margin-right: var(--sp-1); }
/* The portal's icons (assets/js/icons.js): Bootstrap Icons outline glyphs, one family everywhere. */
.pi { display: block; flex: none; font-size: 1.1rem; line-height: 1; }
.icon-chip .pi { font-size: 1.1rem; }
.icon-chip-md { width: 2.6rem; height: 2.6rem; border-radius: var(--r-lg); }
.icon-chip-md .pi { font-size: 1.3rem; }
.icon-chip-lg .pi { font-size: 1.4rem; }
.btn-ico { display: inline-flex; align-items: center; gap: .4rem; }
.btn-ico .pi { font-size: 1rem; }
/* A page's title icon: a gold metal square. */
.page-toolbar .icon-chip { background: var(--highlight-icon-bg); border-color: var(--highlight-icon-border); color: var(--highlight-icon-text); }
.btn-icon {
    display: inline-grid; place-items: center;
    width: 2.25rem; height: 2.25rem;
    border: 1px solid var(--gsl-border); border-radius: var(--r-md);
    background: transparent; color: var(--gsl-accent);
}
.btn-icon:hover { background: var(--gsl-gold-faint); border-color: var(--gsl-gold); }
.btn-icon .pi { font-size: 1.1rem; }

/* -- Panels and cards -- */
.panel {
    background: var(--gsl-card-bg);
    box-shadow: var(--gsl-card-shadow);
}
.panel-border {
    border-color: var(--gsl-border) !important;
}
.card-label {
    color: var(--gsl-accent);
}
/* A table's frame: the panel around it goes light too, so no dark sliver shows at the rounded edge. */
.panel:has(> .table),
.panel:has(> .overflow-auto > .table),
.panel:has(> .table-responsive > .table) {
    background: var(--paper);
}
.code-block {
    color: var(--text-muted-on-frame);
    border: 1px solid var(--a-gold-18);
    border-radius: var(--r-md);
    font-family: var(--mono);
    font-size: .82rem;
}
.code-block--error {
    color: var(--danger-on-dark);
}
/* Panels: in the dark theme, near-black with a gold edge - the frame the cream fields sit in. */
.panel:not(:has(.table)) {
    background: linear-gradient(180deg, var(--a-panel-hi-92) 0%, var(--a-panel-lo-96) 100%);
    border-color: var(--a-gold-45) !important;
}
.code-block {
    background: var(--pine-deep);
}
/* At rest: one even polish over the whole surface - a crisp light top edge and a soft light that
   falls from the top-left corner. On hover (or keyboard focus) a single catch-light glides across
   once. No resting streaks. Reduced motion keeps the polish and drops the glide. */
.stat-tile, .icon-chip, .import-card.ic, .file-card {
    position: relative;
    overflow: hidden;
    isolation: isolate;
}
.stat-tile::after, .icon-chip::after,
.import-card.ic::after, .file-card::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    z-index: 2;
    box-shadow: inset 0 1px 0 var(--a-white-38), inset 0 -1px 0 var(--a-black-20);
    background:
        linear-gradient(105deg, transparent 0 42%, var(--a-white-6) 45%, var(--a-sheen-32) 48%, var(--a-white-6) 51%, transparent 54% 100%),
        linear-gradient(135deg, var(--a-white-14) 0%, var(--a-white-4) 40%, transparent 65%, var(--a-black-8) 100%);
    background-size: 300% 100%, auto;
    background-repeat: no-repeat;
    background-position: 110% 0, 0 0;   /* catch-light parked just off the left edge */
}
.stat-tile:hover::after,
.import-card.ic:hover::after, .file-card:hover::after {
    animation: sterling-glide 1.2s cubic-bezier(.3, .6, .2, 1) 1;
}
@keyframes sterling-glide {
    from { background-position: 110% 0, 0 0; }
    to   { background-position: -10% 0, 0 0; }
}
/* The sheen lies on the surface, under the content, so it never washes out text or buttons */
.stat-tile > *, .import-card.ic > *, .file-card > * { position: relative; z-index: 3; }
.icon-chip > .pi, .icon-chip > i { position: relative; z-index: 3; }
/* Cream cards: just the edge and lacquer, the catch-light only on hover */
.import-card.ic::after, .file-card::after { opacity: .7; }
/* Icon chips: a small polished bead */
.icon-chip::after {
    opacity: 1;
    background:
        radial-gradient(ellipse 90% 60% at 30% 0%, var(--a-white-45), transparent 70%),
        linear-gradient(180deg, transparent 55%, var(--a-black-20) 100%);
    background-size: auto;
    background-position: 0 0;
    box-shadow: inset 0 1px 0 var(--a-white-50);
}
@media (prefers-reduced-motion: reduce) {
    .stat-tile::after, .import-card.ic::after, .file-card::after { animation: none !important; }
}
/* The Browse panel's toolbar is the shared .gsl-toolbar, flush inside its panel. */
.browse-toolbar.gsl-toolbar { border-width: 0 0 1px; border-radius: 0; box-shadow: none; }
.browse-toolbar .btn { height: 2.6rem; }
/* Settings -> Apps: the colour control in the category sheet (1.6). Sixteen preset colours as rectangular
   swatches, eight to a row, each named; the chosen one wears a cream ring and a tick. Under them, the
   picker for any other colour (its well shows the colour it holds), the hex field, and No colour. */
.cat-dialog { max-width: 560px; }
.color-pick { display: grid; gap: 10px; }
.color-pick-grid {
    display: grid;
    grid-template-columns: repeat(8, minmax(0, 1fr));
    gap: var(--swatch-gap);
}
.color-swatch {
    position: relative;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    height: var(--swatch-height);
    padding: 0 2px 3px;
    border: 0;
    border-radius: var(--swatch-radius);
    background: var(--swatch);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .12), 0 1px 2px rgba(0, 0, 0, .35);
    cursor: pointer;
    transition: transform .12s ease, box-shadow .12s ease;
}
.color-swatch:hover { transform: translateY(-1px); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .25), 0 3px 8px rgba(0, 0, 0, .4); }
.color-swatch[aria-checked="true"] {
    box-shadow: 0 0 0 2px var(--paper), 0 0 0 4px var(--swatch-ring-on);
    z-index: 1;
}
.color-swatch:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }
.color-swatch-name {
    font-family: var(--mono);
    font-size: .56rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .78);
    text-shadow: 0 1px 1px rgba(0, 0, 0, .5);
    white-space: nowrap;
    overflow: hidden;
    max-width: 100%;
}
.color-swatch-tick {
    position: absolute;
    top: 4px;
    left: 0;
    right: 0;
    font-size: 1rem;
    line-height: 1;
    color: var(--cream);
    text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
}
.color-pick-custom { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.color-pick-well {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 3px 10px 3px 3px;
    border: 1px solid var(--gsl-border);
    border-radius: 6px;
    background: var(--gsl-surface-2);
    cursor: pointer;
    font-size: .8rem;
    color: var(--gsl-txt-muted);
}
.color-pick-well.is-on { box-shadow: 0 0 0 2px var(--paper), 0 0 0 4px var(--swatch-ring-on); color: var(--gsl-txt); }
.color-pick-well input[type="color"] {
    width: 34px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: 4px;
    background: transparent;
    cursor: pointer;
}
.color-pick-well input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.color-pick-well input[type="color"]::-webkit-color-swatch { border: 0; border-radius: 4px; }
.color-pick-hex { width: 7.5rem; text-transform: uppercase; }
.color-pick-none[aria-pressed="true"] { background: var(--gsl-gold-faint); border-color: var(--gsl-gold); color: var(--gsl-txt); }
.color-pick-says { display: flex; align-items: center; gap: 8px; min-height: 20px; }
.color-pick-chip {
    display: inline-block;
    flex: none;
    width: 18px;
    height: 18px;
    border-radius: 4px;
    background: var(--swatch);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .18);
}
.color-pick-chip.is-none {
    background: repeating-linear-gradient(45deg, transparent 0 4px, var(--a-gold-30) 4px 6px);
    box-shadow: inset 0 0 0 1px var(--a-gold-50);
}
@media (max-width: 575.98px) {
    .color-pick-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .color-swatch-name { font-size: .5rem; }
}

/* -- Tiles -- */
.tile-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--tile-min-width)), 1fr));
    gap: var(--tile-gap);
}
/* Tiles (the price sheets' hub tile): flat cream on the ink ground, a gold shimmer edge along the top, the
   art above, then the app's name centered in serif. One look for every app and portal page. */
.app-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--card-bg);
    border-radius: var(--card-radius);
    box-shadow: var(--card-shadow);
    color: var(--card-title-color);
    text-decoration: none;
    transition: transform .2s ease, box-shadow .2s ease;
}
/* Under the pointer, or under a finger before the tap lands (:active), the tile grows a little and
   its glow brightens. */
.app-tile:hover,
.app-tile:focus-visible,
.app-tile:active {
    transform: scale(var(--card-grow));
    box-shadow: var(--card-shadow-hover);
    color: var(--card-title-color);
}
.app-tile:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 3px;
}
.app-tile[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) {
    .app-tile { transition: none; }
    .app-tile:hover, .app-tile:focus-visible { transform: none; }
}
/* The art. An uploaded image is shown as it was made: no mask, no tint. */
.app-art {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    height: var(--card-art-height);
    background: var(--card-art-bg);
    color: var(--card-art-icon);
    font-size: var(--card-art-glyph-size);
    line-height: 1;
}
.app-art img {
    display: block;
    max-width: var(--card-art-image-max);
    max-height: var(--card-art-image-max);
    width: auto;
    height: auto;
}
/* A screenshot or photo (a JPEG) fills the whole art area, cropped to fit. */
.app-art.is-photo { background: var(--card-art-bg-dark); }
.app-art.is-photo img { width: 100%; height: 100%; max-width: none; max-height: none; object-fit: cover; object-position: top center; }
/* Settings' small copy of the card (the Apps list, and the editor's live preview): the same tile,
   scaled, never a link. */
.app-tile-mini {
    --card-art-height: 54px;
    --card-art-glyph-size: 22px;
    --card-art-icon-size: 22px;
    --card-title-size: 11px;
    --card-padding: 6px 6px 7px;
    width: 7.5rem;
    cursor: default;
    pointer-events: none;
}
.app-tile-mini:hover { transform: none; box-shadow: var(--card-shadow); }
.app-tile-mini .app-art img { max-width: 78%; max-height: 78%; }
.app-tile-mini .app-art .custom-icon { width: var(--card-art-icon-size); height: var(--card-art-icon-size); }
.app-tile-mini-lg {
    --card-art-height: 132px;
    --card-art-glyph-size: 44px;
    --card-art-icon-size: 44px;
    --card-title-size: 16px;
    --card-padding: 12px 12px 14px;
    width: 15rem;
}
.app-card-preview { display: flex; }
/* The edit-app sheet is wide on anything but a phone: Bootstrap's xl width only kicks in at 1200px,
   and an iPad sits below that. */
@media (min-width: 576px) {
    #editAppModal .modal-dialog { max-width: min(1140px, calc(100vw - 2rem)); }
}
/* A logo saved on a white box (detected from its pixels) blends into the art's cream. */
.app-art.on-white img { mix-blend-mode: multiply; }
/* A logo that only exists in white, or sits on its own dark ground (detected the same way): the dark ground. */
.app-art.on-plate { background: var(--card-art-bg-dark); }
.app-art .custom-icon { display: inline-flex; width: var(--card-art-icon-size); height: var(--card-art-icon-size); }
.app-art .custom-icon svg { width: 100%; height: 100%; stroke-width: var(--card-art-icon-stroke); }
.app-art .pi { font-size: inherit; }
.app-art .monogram { font-family: var(--serif); font-weight: 600; }
.app-tile-body {
    display: flex;
    flex: 1 1 auto;                /* takes the rest of the tile's height ... */
    flex-direction: column;
    justify-content: center;       /* ... and the name sits in the middle of it, one line or two */
    gap: 10px;
    min-width: 0;
    padding: var(--card-padding);
    background: linear-gradient(180deg, var(--card-body-top) 0%, var(--card-body-mid) 30%, color-mix(in srgb, var(--tag, var(--card-body-bg)) var(--card-foot-tint), var(--black)) 100%);
    border-top: 1px solid var(--card-body-rule);
}
.app-tile-title {
    font-family: var(--serif);
    font-size: var(--card-title-size);
    font-weight: 600;
    line-height: 1.15;
    text-wrap: balance;
    text-align: center;
    color: var(--card-title-color);
}
@media (max-width: 575.98px) {
    .tile-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* A tile and its favorite mark share one cell, so the mark is a button beside the link and rises with it. */
.app-cell { position: relative; display: flex; min-width: 0; }
.app-cell[hidden] { display: none; }
.app-cell > .app-tile { flex: 1; min-width: 0; }
.app-cell:hover > .app-tile,
.app-cell:active > .app-tile {
    transform: scale(var(--card-grow));
    box-shadow: var(--card-shadow-hover);
}
/* The favorite mark sits in the tile's bottom-right corner (Allan, 2026-10-29) and moves out with the
   tile's corner as the tile grows under the pointer. */
.fav-mark {
    position: absolute;
    bottom: 0;
    right: 0;
    z-index: 2;
    display: flex;
    align-items: flex-end;
    justify-content: flex-end;
    width: 40px;
    height: 40px;
    padding: 0 var(--fav-inset) var(--fav-inset) 0;
    border: 0;
    background: none;
    cursor: pointer;
    transition: transform .2s ease;
}
.app-cell:hover > .fav-mark,
.app-cell:active > .fav-mark,
.app-tile:focus-visible + .fav-mark { transform: translate(4px, 4px); }
.fav-mark:focus-visible { outline: 0; }
.fav-mark:focus-visible .fav-seal {
    border-radius: 50%;
    outline: 2px solid var(--gold-d);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--cream);
}
.fav-seal {
    display: block;
    flex: none;
    width: var(--fav-size);
    height: var(--fav-size);
    background: var(--fav-mark-idle) center / contain no-repeat;
    opacity: var(--fav-idle-opacity);
    transition: opacity .2s ease;
}
.fav-mark:hover .fav-seal,
.fav-mark:focus-visible .fav-seal { opacity: var(--fav-hover-opacity); }
.fav-mark[aria-pressed="true"] .fav-seal,
.fav-toggle[aria-pressed="true"] .fav-seal { background-image: var(--fav-mark); opacity: 1; }
/* The grip (drag handle): six gold dots. On a card it sits in the bottom-left corner of the black
   foot, mirroring the favorite seal bottom-right, and shows on hover or focus; on a category it sits
   before the heading. A finger can't hover, so on touch screens it is always faintly there. While a
   drag is on, the moved card or category fades in place and a copy of it follows the pointer. */
.drag-grip {
    position: absolute;
    bottom: 0;
    left: 0;
    z-index: 2;
    display: flex;
    align-items: flex-end;
    width: 40px;
    height: 40px;
    padding: 0 0 var(--fav-inset) var(--fav-inset);
    border: 0;
    background: none;
    cursor: grab;
    touch-action: none;
    opacity: 0;
    transition: opacity .2s ease, transform .2s ease;
}
.drag-grip-dots {
    display: block;
    width: 10px;
    height: 16px;
    background: radial-gradient(circle, var(--gold-b) 1.4px, transparent 1.6px) 0 0 / 5px 5.33px repeat;
}
.app-cell:hover > .drag-grip,
.app-cell:focus-within > .drag-grip,
.drag-grip:focus-visible { opacity: var(--fav-hover-opacity); }
.app-cell:hover > .drag-grip,
.app-cell:active > .drag-grip { transform: translate(-4px, 4px); }   /* out with the tile's corner as it grows */
.drag-grip:hover { opacity: 1; }
.drag-grip:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -6px; border-radius: 6px; }
.app-group-head > .drag-grip {
    position: static;
    width: 24px;
    height: 24px;
    padding: 4px 0 0;
    margin-inline-end: -4px;
    align-items: flex-start;
}
.app-group-head:hover > .drag-grip,
.app-group-head:focus-within > .drag-grip { opacity: var(--fav-hover-opacity); }
@media (hover: none) {
    .drag-grip, .app-group-head > .drag-grip { opacity: .45; }
}
.is-dragging { opacity: .3; }
.is-dragging > .app-tile, .is-dragging .app-tile { box-shadow: none; transform: none; }
.drag-ghost {
    position: fixed;
    z-index: 1200;
    margin: 0;
    opacity: .92;
    pointer-events: none;
    filter: drop-shadow(0 18px 28px rgba(0, 0, 0, .45));
    will-change: transform;
}
.drag-ghost > .drag-grip, .drag-ghost .drag-grip { opacity: 1; }
.drag-ghost.app-group { box-sizing: border-box; background: var(--ink1); padding: 8px; border-radius: var(--card-radius); overflow: hidden; }
body.is-reordering { cursor: grabbing; user-select: none; -webkit-user-select: none; touch-action: none; }
body.is-reordering .drag-grip { cursor: grabbing; }
@media (prefers-reduced-motion: reduce) {
    .drag-grip { transition: none; }
    .app-cell:hover > .drag-grip { transform: none; }
    .fav-mark, .fav-seal, .fav-toggle, .fav-switch, .fav-switch::after { transition: none; }
    .app-cell:hover > .app-tile,
    .app-cell:hover > .fav-mark,
    .app-tile:focus-visible + .fav-mark { transform: none; }
}
/* Favorites only: the black plate beside the lede. Its upright switch slides up and turns gold when on. */
.fav-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-3);
    min-height: var(--fav-toggle-height);
    margin-left: auto;
    padding: 0 var(--sp-3) 0 var(--sp-4);
    background: var(--fav-toggle-bg);
    border: 1px solid var(--fav-toggle-border);
    border-radius: var(--r-xl);
    color: var(--fav-toggle-text);
    font-family: var(--mono);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    cursor: pointer;
    box-shadow: 0 2px 10px var(--a-black-30);
    transition: border-color .2s ease, box-shadow .2s ease, transform .15s ease;
}
.fav-toggle:hover { transform: translateY(-1px); box-shadow: 0 4px 14px var(--a-black-30), 0 0 12px var(--a-gold-30); }
.fav-toggle[aria-pressed="true"] {
    background: var(--fav-toggle-bg-on);
    border-color: var(--fav-toggle-border-on);
    box-shadow: var(--fav-toggle-glow-on), 0 2px 10px var(--a-black-30);
}
.fav-toggle:focus-visible { outline: 2px solid var(--cream); outline-offset: 2px; }
/* The seal: blacked out while the switch is off, full colour and lit while it is on. */
.fav-toggle .fav-seal { width: 25px; height: 25px; opacity: 1; filter: var(--fav-toggle-seal-off); transition: filter .25s ease, transform .25s ease; }
.fav-toggle[aria-pressed="true"] .fav-seal { filter: var(--fav-toggle-seal-on); transform: scale(1.08); }
.fav-switch {
    position: relative;
    flex: none;
    width: var(--fav-switch-width);
    height: var(--fav-switch-height);
    margin-left: var(--sp-1);
    border-radius: var(--fav-switch-width);
    background: var(--fav-switch-track);
    transition: background .2s ease;
}
.fav-switch::after {
    content: "";
    position: absolute;
    left: 3px;
    bottom: 3px;
    width: calc(var(--fav-switch-width) - 6px);
    height: calc(var(--fav-switch-width) - 6px);
    border-radius: 50%;
    background: var(--fav-switch-knob);
    transition: transform .2s ease, background .2s ease;
}
.fav-toggle[aria-pressed="true"] .fav-switch { background: var(--fav-switch-track-on); }
.fav-toggle[aria-pressed="true"] .fav-switch::after {
    background: var(--fav-switch-knob-on);
    transform: translateY(calc(var(--fav-switch-width) - var(--fav-switch-height)));
}
/* An app's icon on a disc (Settings -> Apps: the list and the editor's preview). Quiet by default (gold-tint
   disc, thin gold ring, dark line icon); a row's icon_color gives it a heritage tone. */
.app-medal {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--medallion-size);
    height: var(--medallion-size);
    border-radius: 50%;
    background: var(--medallion-bg);
    box-shadow: var(--medallion-ring);
    color: var(--medallion-icon);
    font-size: var(--medallion-icon-size);
    line-height: 1;
}
.app-medal.tone-forest  { --medallion-bg: var(--tone-forest);  --medallion-icon: var(--medallion-icon-on-tone); }
.app-medal.tone-oxblood { --medallion-bg: var(--tone-oxblood); --medallion-icon: var(--medallion-icon-on-tone); }
.app-medal.tone-barn    { --medallion-bg: var(--tone-barn);    --medallion-icon: var(--medallion-icon-on-tone); }
.app-medal.tone-navy    { --medallion-bg: var(--tone-navy);    --medallion-icon: var(--medallion-icon-on-tone); }
.app-medal.tone-sage    { --medallion-bg: var(--tone-sage);    --medallion-icon: var(--medallion-icon-on-tone); }
.app-medal.tone-bronze  { --medallion-bg: var(--tone-bronze);  --medallion-icon: var(--control-metal-text); }
.app-medal .custom-icon { display: inline-flex; width: var(--medallion-custom-icon-size); height: var(--medallion-custom-icon-size); }
.app-medal-sm .custom-icon { width: 1.15em; height: 1.15em; }
.app-medal .custom-icon svg { width: 100%; height: 100%; }
.app-medal-sm { width: 32px; height: 32px; font-size: 15px; flex: none; }
.dash-empty {
    padding: var(--sp-6);
    text-align: center;
    border: 1px dashed var(--gsl-border);
    border-radius: var(--r-xl);
    color: var(--gsl-txt-soft);
}

/* -- Forms -- */
.form-control,
.form-select {
    background-color: var(--gsl-surface);
    border-color: var(--gsl-border);
    color: var(--gsl-txt);
}
.form-control:focus,
.form-select:focus {
    background-color: var(--gsl-surface);
    border-color: var(--gsl-gold);
    box-shadow: 0 0 0 .25rem var(--gsl-gold-faint);
    color: var(--gsl-txt);
}
.form-control::placeholder {
    color: var(--gsl-txt-soft);
}
/* Inputs are cream-filled with a gold edge in BOTH themes; on the dark theme that is what makes a form
   readable at a glance (dark panel, light fields), exactly as the client's quote editor does it. */
main .form-control,
main .form-select {
    border: 1px solid var(--field-edge);
    border-radius: var(--r-lg);
    box-shadow: 0 1px 2px var(--a-ink-text-6) inset;
}
main .form-control,
main .form-select {
    color-scheme: light;
    background-color: var(--field);
    border-color: var(--a-gold-75);
    color: var(--text-on-card);
    /* Bootstrap swaps the select caret to a light one in dark mode; on a cream field it needs the dark one. */
    --bs-form-select-bg-img: var(--select-caret-on-cream);
}
main .form-control::placeholder {
    color: var(--placeholder);
}
main .form-control:focus,
main .form-select:focus {
    background-color: var(--field-focus);
    border-color: var(--gold);
    box-shadow: 0 0 0 .2rem var(--a-gold-30);
    color: var(--text-on-card);
}
main .form-control:not(.form-control-sm),
main .form-select:not(.form-select-sm) {
    min-height: 2.75rem;
    padding-left: .9rem;
}
main label:not(.form-check-label) {
    font-family: var(--mono);
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--gsl-accent);
}
.form-check-input {
    background-color: var(--gsl-surface);
    border-color: var(--gsl-border-strong);
}
.form-check-input:checked {
    background-color: var(--gsl-gold);
    border-color: var(--gsl-gold);
}
.form-check-input:focus {
    border-color: var(--gsl-gold);
    box-shadow: 0 0 0 .25rem var(--gsl-gold-faint);
}
.form-check-input:not(:checked) { background-color: var(--paper-cream); border-color: var(--rule-s); }
/* Labels beside a switch or checkbox on a cream surface read in the card text color. */
.on-cream .form-check-label { color: var(--text-on-card); }

/* -- Tables -- */
/* The client's own apps keep their data tables light even on a dark page: rows are easiest to scan
   dark-on-cream. So in the dark theme every table re-declares the light roles for itself - text,
   muted text, accent, form controls and code all fall back to their light values inside it. */
.table {
    --gsl-table-bg: var(--paper);
    --gsl-table-stripe: var(--table-stripe);
    --gsl-table-hover: var(--a-gold-deep-10);
    --gsl-table-rule: var(--table-rule);
    --bs-table-bg: var(--gsl-table-bg);
    --bs-table-color: var(--text-on-card);
    --bs-table-striped-bg: var(--gsl-table-stripe);
    --bs-table-striped-color: var(--text-on-card);
    --bs-table-hover-bg: var(--gsl-table-hover);
    --bs-table-hover-color: var(--text-on-card);
    --bs-table-border-color: var(--gsl-table-rule);
    font-size: .9rem;
}
.table-head th {
    position: sticky;
    top: 0;
    z-index: 1;
    font-family: var(--mono);
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .2em;
    line-height: 1.5;
    text-transform: uppercase;
    vertical-align: middle;
    padding-top: .95rem !important;
    padding-bottom: .95rem !important;
}
.table tbody tr:nth-child(odd) > td {
    background-color: var(--gsl-table-stripe);
}
.table tbody td {
    vertical-align: middle;
    color: var(--text-on-card);
}
/* Generous rows, as in the client's apps - table-sm included, because every portal table uses it. */
.table > tbody > tr > td,
.table-sm > tbody > tr > td {
    padding: .8rem .9rem;
}
.table > thead > tr > th,
.table-sm > thead > tr > th {
    padding-left: .9rem;
    padding-right: .9rem;
}
/* Tables sit flush inside p-0 panels; keep the first and last columns off the panel edge. */
.table > :not(caption) > * > :first-child { padding-left: var(--sp-3); }
.table > :not(caption) > * > :last-child { padding-right: var(--sp-3); }
.table-head th {
    /* The rich gold heading bar (as on the client's own tables). */
    background: var(--gold-bar);
    color: var(--gold-bar-ink);
    border-bottom: 1px solid var(--gold-bar-edge) !important;
    box-shadow: inset 0 1px 0 var(--a-white-25);
}
.gsl-table {
    --bs-table-bg: transparent;
    border-collapse: collapse;
    color: var(--table-cell-text);
    font-variant-numeric: tabular-nums;
}
.gsl-table > thead th,
.table.gsl-table .table-head th {
    font-family: var(--mono);
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    text-align: center;
    vertical-align: middle;
    color: var(--table-head-text);
    background: var(--table-head-bg);
    border: 0;
    border-bottom: 0 !important;
    box-shadow: none;
    padding: .95rem .9rem !important;
}
.gsl-table > thead tr.gsl-groups th {
    background: transparent;
    padding: 0 1px !important;
}
.gsl-table > thead tr.gsl-groups th > span {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 2.4rem;
    background: var(--table-group-bg);
    color: var(--table-group-text);
    border: 1px solid var(--table-group-border);
    border-bottom: none;
    text-shadow: 0 1px 0 var(--black);
    letter-spacing: .2em;
}
.gsl-table > tbody > tr > td {
    text-align: center;
    vertical-align: middle;
    color: var(--text-on-card);
    border-bottom: 1px solid var(--table-cell-rule);
    padding: .85rem .9rem;
}
.gsl-table > tbody > tr:nth-child(odd) > td { background-color: var(--table-row-odd); }
.gsl-table > tbody > tr:nth-child(even) > td { background-color: var(--table-row-even); }
.gsl-table > tbody > tr:last-child > td { border-bottom: none; }
.gsl-table.table-hover > tbody > tr:hover > td { background-color: var(--table-row-hover); }
.gsl-table th.gstart,
.gsl-table td.gstart { border-left: 1px solid var(--table-group-rule); }
.gsl-table td.num,
.gsl-table th.num {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
}
/* The key column: monospace, bold, deep gold-brown (the price sheets' SKU); a gray subtitle under it. */
.gsl-table td.gsl-key {
    font-family: var(--mono);
    font-weight: 700;
    letter-spacing: .04em;
    color: var(--table-key-text);
}
.gsl-table td.gsl-key .gsl-sub,
.gsl-table td.gsl-key .small {
    display: block;
    font-family: var(--sans);
    font-weight: 400;
    letter-spacing: .01em;
    color: var(--table-sub-text);   /* the sheets' lighter gray is 3.4:1 here; this is the AA step darker */
}
/* A person's name opens what they are assigned to. It is a name first and a
   control second: the sans face at the table's own size, and no underline until
   it is hovered or reached by the keyboard. */
.gsl-table td .open-person {
    font-family: var(--sans);
    font-weight: 600;
    font-size: .9rem;
    letter-spacing: 0;
    color: var(--table-key-text);
    text-decoration: none;
}
.gsl-table td .open-person:hover { text-decoration: none; }
.gsl-table td .open-person:focus-visible {
    text-decoration: none;
    outline: 2px solid var(--table-key-text);
    outline-offset: 3px;
    border-radius: 2px;
}

/* A name is a name: the sans face at the table's own size, no underline and no
   button dress. What opens the person is the View button at the end of the row,
   which is there at rest, so nothing has to be hovered to be found and a phone,
   which cannot hover at all, shows the same thing a desktop does. The whole row
   is a target too, for anyone who clicks the middle of it. */
#users-table td.gsl-key .person-name {
    font-family: var(--sans);
    font-weight: 600;
    font-size: .9rem;
    letter-spacing: 0;
    color: var(--table-key-text);
}
#users-table tbody tr[data-user-id] { cursor: pointer; }
#users-table th.go-head,
#users-table td.go {
    width: 5.5rem;
    text-align: right;
    padding-right: .85rem;
    white-space: nowrap;
}
#users-table td.go .open-person {
    font-family: var(--mono);
    font-size: .68rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    padding: .2rem .6rem;
    text-decoration: none;
}
/* On a phone the fixed layout squeezed the name to a couple of letters, because
   the access-groups column holds its 14rem whatever the screen is. Below the
   tablet break the columns size to their content instead and the panel scrolls
   sideways, with the View column pinned to the right edge so the way into a
   person is on screen before any scrolling. */
@media (max-width: 767.98px) {
    #users-table { table-layout: auto !important; min-width: 33rem; }
    #users-head th:nth-child(2) { width: auto !important; }
    #users-table td.gsl-key { min-width: 9.5rem; }
    #users-table th.go-head,
    #users-table td.go {
        position: sticky;
        right: 0;
        z-index: 2;
        width: 4.75rem;
        padding-right: .5rem;
    }
    #users-table td.go {
        background-color: var(--gsl-table-bg);
        box-shadow: -8px 0 8px -8px rgba(0, 0, 0, .25);
    }
    #users-table tbody tr:nth-child(odd) > td.go { background-color: var(--gsl-table-stripe); }
    #users-table th.go-head { background: var(--gold-bar); }
    #users-table td.go .open-person { padding: .25rem .45rem; }
}

/* The same for the count that opens who is in a group: a figure to read, not a
   line of blue rule across the column. */
/* The head count is the way into a group, so it is a control at rest in the
   same family as a person's View button, not a figure that turns into a link
   when something hovers it. The whole group row opens it too. */
#groups-table tbody tr[data-group-id] { cursor: pointer; }
.gsl-table td .open-members {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
    font-size: .72rem;
    letter-spacing: .04em;
    padding: .2rem .55rem;
    text-decoration: none;
}
.gsl-table td .open-members i { font-size: .72rem; opacity: .75; }

.gsl-table code { color: var(--code); }
/* Fields inside a table, and in cream dialogs: the sheets' cost-table inputs. */
.gsl-table .form-control,
.gsl-table .form-select,
main .gsl-table .form-control:not(.form-control-sm),
.modal-content .form-control,
.modal-content .form-select,
main .modal-content .form-control,
main .modal-content .form-select,
main .on-cream .form-control,
main .on-cream .form-select {
    background-color: var(--field-bg-on-cream);
    border: 1px solid var(--field-border-on-cream);
    border-radius: var(--r-md);
    color: var(--field-text-on-cream);
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
    box-shadow: none;
}
.gsl-table .form-control:focus,
.gsl-table .form-select:focus,
.modal-content .form-control:focus,
.modal-content .form-select:focus,
main .on-cream .form-control:focus,
main .on-cream .form-select:focus,
main .modal-content .form-control:focus,
main .modal-content .form-select:focus {
    background-color: var(--paper);
    border-color: var(--gold);
    box-shadow: 0 0 0 2px var(--field-focus-glow-on-cream);
    outline: 2px solid var(--focus-ring);
    outline-offset: 1px;
}
.gsl-table .form-check-input { accent-color: var(--gold-b); border-color: var(--field-border-on-cream); }
/* Column alignment by content (Portal.alignColumns, tables marked data-auto-align): text left, numbers
   right and tabular, short codes and 0/1 flags centered. Header cells follow their column. */
.table.gsl-table .table-head th.col-text, .gsl-table > thead th.col-text, .gsl-table td.col-text { text-align: left; }
.table.gsl-table .table-head th.col-num, .gsl-table > thead th.col-num, .gsl-table td.col-num { text-align: right; }
.gsl-table td.col-num { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.table.gsl-table .table-head th.col-code, .gsl-table > thead th.col-code, .gsl-table td.col-code { text-align: center; }
.gsl-table td.col-text {
    white-space: nowrap;
    max-width: var(--table-text-max-width);
    overflow: hidden;
    text-overflow: ellipsis;
}

/* -- Toolbars -- */
.gsl-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 14px;
    row-gap: 8px;
    padding: 10px 18px;
    background: var(--toolbar-bg);
    border: 1px solid var(--gold-line);
    border-bottom: 1px solid var(--toolbar-rule);
    border-radius: var(--r-lg);
    box-shadow: 0 8px 28px var(--a-black-35);
}
.gsl-label,
.gsl-toolbar label,
main .gsl-toolbar label:not(.form-check-label) {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    margin: 0;
    font-family: var(--mono);
    font-size: .66rem;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--toolbar-label);    /* the sheets' gray is 3:1 on this green; this passes AA */
}
.gsl-status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: var(--r-lg);
    border: 1px solid var(--a-gold-50);
    font-family: var(--mono);
    font-size: .66rem;
    letter-spacing: .14em;
    color: var(--gold-b);
}
.gsl-status::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--status-ok);
    box-shadow: 0 0 6px var(--status-ok-glow);
}
.gsl-status.off::before { background: var(--status-off); box-shadow: 0 0 6px var(--status-off-glow); }
main .gsl-form .form-select option,
main .gsl-toolbar .form-select option { color: var(--text-on-card); background: var(--cream); }
main .gsl-form .form-control::placeholder,
main .gsl-toolbar .form-control::placeholder { color: var(--text-faint-on-frame); }

/* -- Off-canvas -- */
.offcanvas {
    --bs-offcanvas-bg: var(--gsl-surface);
    --bs-offcanvas-color: var(--gsl-txt);
    --bs-offcanvas-border-color: var(--gsl-border);
}

/* -- Tabs -- */
/* A page's sibling views (Settings): the order form's tab bar, across the top under the title.
   A cream track; the chosen tab is the deep green with gold lettering; counts in small badges. */
.portal-tabs {
    display: flex;
    flex-wrap: wrap;
    width: fit-content;
    max-width: 100%;
    margin: 0 0 var(--sp-5);
    padding: 0;
    list-style: none;
    background: var(--gold-tint);
    border: 1px solid var(--card-border);
    border-radius: var(--r-md);
    overflow: hidden;
    box-shadow: var(--card-shadow);
}
.portal-tabs .nav-link {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    margin: 0;
    padding: 10px 20px;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--text-on-card);
    font-family: var(--mono);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    transition: background .14s ease, color .14s ease;
}
.portal-tabs .nav-item + .nav-item .nav-link { border-left: 1px solid var(--rule); }
.portal-tabs .nav-link:hover { background: var(--gold-tint-2); color: var(--text-on-card); }
.portal-tabs .nav-link.active { background: var(--ink3); color: var(--gold-b); box-shadow: inset 0 -2px 0 var(--highlight-accent); }
.portal-tabs .nav-link:focus-visible { outline-offset: -3px; }
.tab-count:empty { display: none; }
.tab-count {
    min-width: 1.5rem;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--control-metal-bg);
    border: 1px solid var(--control-metal-border);
    color: var(--control-metal-text);
    font-size: .66rem;
    letter-spacing: .04em;
    text-align: center;
}
@media (max-width: 575.98px) {
    /* One row that scrolls sideways inside the page, never past it. */
    .portal-tabs { width: 100%; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
    .portal-tabs::-webkit-scrollbar { display: none; }
    .portal-tabs .nav-item { flex: 0 0 auto; }
    .portal-tabs .nav-link { min-height: 44px; padding: 10px 14px; letter-spacing: .12em; white-space: nowrap; }
}

/* -- Toasts -- */
.toast-container {
    position: fixed;
    top: calc(var(--header-h) + 1rem);
    right: 1rem;
    z-index: 1100;
    display: flex;
    flex-direction: column;
    gap: .5rem;
}
.toast-message {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    max-width: 22rem;
    padding: .65rem .85rem;
    border-radius: var(--r-lg);
    background: var(--gsl-surface);
    border: 1px solid var(--gsl-border);
    color: var(--gsl-txt);
    box-shadow: var(--sh-3);
    opacity: 0;
    transform: translateY(-.3rem);
    transition: opacity .2s ease, transform .2s ease;
}
.toast-message.show {
    opacity: 1;
    transform: translateY(0);
}
.toast-message.hiding {
    opacity: 0;
}
.toast-message .toast-body {
    flex: 1;
    font-size: .9rem;
}
.toast-message .toast-title {
    display: block;
    font-weight: 600;
    color: var(--gsl-gold);
    margin-bottom: .1rem;
}
.toast-message .toast-close {
    border: 0;
    background: transparent;
    color: var(--gsl-txt-soft);
    opacity: .7;
    line-height: 1;
    padding: 0;
}
.toast-message.toast-success { border-left: 3px solid var(--success); }
.toast-message.toast-danger,
.toast-message.toast-error { border-left: 3px solid var(--gsl-danger); }
.toast-message.toast-warning { border-left: 3px solid var(--gsl-gold); }

/* -- Dialogs -- */
.btn-close {
    filter: invert(1) grayscale(100%) brightness(200%);
}
.modal-content {
    background-color: var(--gsl-surface);
    color: var(--gsl-txt);
}
.modal-header,
.modal-footer {
    border-color: var(--gsl-border-soft);
}
.modal-title {
    font-family: var(--serif);
    color: var(--gsl-heading);
}
/* Dark theme: dialogs are cream paper like the cards; buttons are never green (green is only for
   "success" badges). */
.modal-content {
    background: linear-gradient(180deg, var(--paper-cream) 0%, var(--paper-cream-2) 100%);
    border-color: var(--a-gold-55);
}
.modal-content .btn-close { filter: none; }
.modal-content .btn-secondary {
    --bs-btn-color: var(--text-on-card);
    --bs-btn-border-color: var(--rule-s);
    --bs-btn-hover-color: var(--text-on-card);
    --bs-btn-hover-bg: var(--a-gold-deep-12);
}
.portal-offsite {
    max-width: 26rem;
    width: calc(100% - 2rem);
    padding: var(--sp-5);
    border: 1px solid var(--a-gold-55);
    border-radius: var(--r-xl);
    background: var(--ink-door);
    color: var(--cream);
    box-shadow: 0 24px 60px var(--a-black-45);
}
.portal-offsite::backdrop { background: var(--a-black-soft-55); backdrop-filter: blur(2px); }
.portal-offsite h2 { font-family: var(--serif); font-size: 1.5rem; color: var(--ink-gold-hi); margin: 0 0 var(--sp-2); }
.portal-offsite p { margin: 0 0 var(--sp-3); color: var(--a-cream-85); }
.portal-offsite-eyebrow {
    font-family: var(--mono);
    font-size: .66rem !important;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--ink-gold) !important;
    margin-bottom: var(--sp-1) !important;
}
.portal-offsite-actions { display: flex; gap: var(--sp-2); justify-content: flex-end; flex-wrap: wrap; }
.portal-offsite .btn-outline-primary { --bs-btn-color: var(--cream); --bs-btn-border-color: var(--a-cream-35); --bs-btn-hover-color: var(--cream); --bs-btn-hover-bg: var(--a-cream-8); }
/* File pickers in cream dialogs: the button reads as the quiet control, not Bootstrap's dark default. */
.modal-content .form-control::file-selector-button,
.on-cream .form-control::file-selector-button {
    background: var(--table-row-even);
    color: var(--field-text-on-cream);
    border-right: 1px solid var(--field-border-on-cream);
}
.on-cream .form-select,
.modal-content .form-select { --bs-form-select-bg-img: var(--select-caret-on-cream); color-scheme: light; }

/* == 5. Screens == */
/* What belongs to one screen: dashboard, Agility Imports, Transfers, Settings, and the Select inspector. */

/* -- Dashboard -- */
/* The welcome, then one section per category (Settings -> Apps -> Group), then the portal's own pages. */
[data-screen="dashboard"] .page-toolbar { padding-top: var(--sp-4); border-bottom: 0; }
/* The welcome has a row to itself; the lede and Favorites only share the next one. */
[data-screen="dashboard"] .page-toolbar h1 { flex-basis: 100%; }
[data-screen="dashboard"] .page-lede { flex: 0 1 60ch; min-width: 0; padding-right: 0; }
@media (max-width: 575.98px) {
    [data-screen="dashboard"] .page-lede { flex-basis: 100%; }
    .fav-toggle { margin-left: 0; }
}
.app-list { display: flow-root; }
.app-group + .app-group,
.app-list + .app-group { margin-top: var(--category-gap); }
.app-group-head {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    margin: 0 0 20px;
}
.app-group-head h2 {
    position: relative;
    margin: 0;
    font-size: var(--category-title-size);
    font-weight: 600;
    line-height: 1.1;
    color: var(--heading-on-frame);
}
/* The category's colour: a short bar under its name (1.5.1, in place of the dot beside it), and the
   same colour at the foot of every card in the section (--tag on the section). */
.app-group.has-tag .app-group-head h2::after {
    content: "";
    position: absolute;
    left: 0;
    top: 100%;
    margin-top: var(--category-bar-gap);
    width: var(--category-bar-width);
    height: var(--category-bar-height);
    border-radius: 2px;
    background: var(--tag);
    box-shadow: 0 0 10px color-mix(in srgb, var(--tag) 60%, transparent);
}
.app-group-head::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--highlight-rule);
    transform: translateY(var(--category-rule-drop));
}

/* -- Settings -> Apps: the admin board (1.6) -- */
/* The pool (apps in no category) on top, then one card per category. Tiles are the small card from the
   edit sheet, and the whole card is the drag handle (1.6.1: no grip, and it does not open the app); under
   it, the Visible switch and Edit.
   A hidden app is dimmed. While a tile is in the air every zone shows its edge (nothing changes size,
   so the page never shifts under the pointer); an empty zone keeps a height, so it is still a target. */
.apps-board { display: grid; gap: var(--sp-4); }
.board-zone {
    position: relative;
    border: 1px solid var(--board-card-border);
    border-radius: var(--board-card-radius);
    background: var(--board-card-bg);
}
.board-pool { border-style: dashed; background: transparent; }
.board-cat-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px 10px 10px;
    border-bottom: 1px solid var(--a-gold-30);
}
.board-cat.has-tag .board-cat-head { border-bottom-width: var(--board-bar-height); border-bottom-color: var(--tag); }
.board-cat-head > .drag-grip {
    position: static;
    flex: none;
    width: 28px;
    height: 28px;
    padding: 0;
    align-items: center;
    justify-content: center;
}
.board-cat-head:hover > .drag-grip,
.board-cat-head:focus-within > .drag-grip { opacity: var(--fav-hover-opacity); }
.board-cat-name,
.board-pool-name {
    flex: 1 1 10rem;
    min-width: 0;
    margin: 0;
    padding: 2px 6px;
    border: 1px solid transparent;
    border-radius: 6px;
    background: transparent;
    font-family: var(--serif);
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--heading-on-frame);
}
.board-pool-name { flex: 0 1 auto; }
.board-cat-name:hover:not([readonly]) { border-color: var(--a-gold-30); }
.board-cat-name:focus { outline: 0; border-color: var(--gsl-gold); background: var(--a-black-30); }
.board-count {
    flex: none;
    padding: 2px 8px;
    border-radius: 1rem;
    background: var(--a-black-30);
    font-family: var(--mono);
    font-size: .68rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--gsl-txt-muted);
}
.board-pool-says { flex: 1 1 100%; }
@media (min-width: 768px) { .board-pool-says { flex: 1 1 auto; text-align: right; } }
.board-cat-color {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid var(--a-gold-30);
    border-radius: 6px;
    background: transparent;
    cursor: pointer;
}
.board-cat-color:hover { border-color: var(--gsl-gold); }
.board-cat-color:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.board-cat-del { flex: none; }
.board-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, var(--board-tile-width));
    gap: var(--board-gap);
    align-items: start;
    min-height: 76px;
    padding: 14px 12px 12px;
}
.board-tiles:empty::after {
    content: "Drop apps here";
    grid-column: 1 / -1;
    align-self: center;
    justify-self: center;
    text-align: center;
    font-size: .8rem;
    color: var(--gsl-txt-muted);
    opacity: .7;
}
.board-tiles-pool:empty::after { content: "Every app has a category."; }
.board-tile { display: grid; align-content: start; gap: 6px; min-width: 0; }
.board-tile[hidden] { display: none; }
.board-tile-card {
    position: relative;
    display: flex;
    border-radius: var(--card-radius);
    cursor: grab;
    touch-action: pan-y;                     /* a vertical swipe over a tile still scrolls; a hold then drags */
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;             /* no image menu on a long press */
}
.board-tile-card[tabindex]:hover .app-tile-mini { box-shadow: var(--card-shadow-hover); }
.board-tile-card:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }
.board-tile .app-tile-mini { width: 100%; }
.board-tile .app-tile-mini img { -webkit-user-drag: none; pointer-events: none; }
body.is-reordering .board-tile-card { cursor: grabbing; }
.board-tile.is-off .board-tile-card { opacity: .45; filter: grayscale(.6); }
.board-tile-bar { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.board-tile-edit { padding: 2px 8px; line-height: 1.2; }
/* The Visible switch: a small gold track that lights when on. */
.board-visible { display: inline-flex; align-items: center; gap: 6px; margin: 0; cursor: pointer; font-size: .72rem; color: var(--gsl-txt-muted); }
.board-visible-input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.board-visible-track {
    position: relative;
    flex: none;
    width: 30px;
    height: 16px;
    border-radius: 8px;
    background: var(--a-black-30);
    box-shadow: inset 0 0 0 1px var(--a-gold-30);
    transition: background .15s ease, box-shadow .15s ease;
}
.board-visible-track::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--gsl-txt-muted);
    transition: transform .15s ease, background .15s ease;
}
.board-visible-input:checked + .board-visible-track { background: var(--gold-d); box-shadow: inset 0 0 0 1px var(--gold-b); }
.board-visible-input:checked + .board-visible-track::after { transform: translateX(14px); background: var(--cream); }
.board-visible-input:focus-visible + .board-visible-track { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.board-visible-input:checked ~ .board-visible-says { color: var(--gsl-txt); }
.board-visible-input:disabled ~ * { cursor: default; opacity: .6; }
.board-cats { display: grid; gap: var(--sp-4); }
.board-add-cat {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 14px;
    border: 1px dashed var(--a-gold-50);
    border-radius: var(--board-card-radius);
    background: transparent;
    color: var(--gsl-gold);
    font-size: .85rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    cursor: pointer;
}
.board-add-cat:hover { background: var(--a-black-30); border-color: var(--gsl-gold); }
.board-add-cat:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.apps-board.is-moving-tile .board-zone { box-shadow: 0 0 0 1px var(--board-drop-ring); }
.drag-ghost.board-cat { background: var(--ink1); overflow: hidden; }
.drag-ghost.board-tile { background: transparent; }
.drag-ghost.board-tile .board-tile-bar { visibility: hidden; }   /* the copy in the air is the card alone */
@media (max-width: 575.98px) {
    .board-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 10px; }
    .board-cat-name, .board-pool-name { font-size: 1.1rem; }
}
@media (prefers-reduced-motion: reduce) {
    .color-swatch, .board-visible-track, .board-visible-track::after { transition: none; }
}

/* -- Agility Imports and Transfers: status cards -- */
/* Health / stat cards */
.import-card,
.file-card,
.stat-card {
    background: var(--gsl-card-bg);
    border: 1px solid var(--gsl-border);
    box-shadow: var(--gsl-card-shadow);
}
.stat-card .stat-value,
.import-card .stat-value {
    font-weight: 700;
    font-family: var(--serif);
    color: var(--gsl-heading);
}
.import-card,
.file-card,
.stat-card {
    position: relative;
    overflow: hidden;
    border-radius: var(--r-xl) !important;
    transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.import-card::before,
.stat-card::before {
    content: "";
    position: absolute;
    left: 0; right: 0; top: 0;
    height: 3px;
    background: linear-gradient(90deg, var(--gsl-gold) 0%, var(--gsl-gold-br) 45%, transparent 100%);
}
.import-card:hover,
.file-card:hover {
    transform: translateY(-2px);
    border-color: var(--gsl-border-strong);
    box-shadow: var(--gsl-card-shadow-hover);
}
.stat-card .stat-value,
.import-card .stat-value {
    font-size: 1.5rem;
    line-height: 1.2;
}
/* Agility Imports cards: head (icon - name + schedule - status), two figures, actions */
.import-card.ic { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-4) !important; }
/* Dark theme: the cards stay cream paper on the green page, as the tables do (the client's
   "cream on dark" pattern). */
.import-card.ic,
.file-card {
    background: linear-gradient(180deg, var(--paper-cream) 0%, var(--paper-cream-2) 100%) !important;
    border-color: var(--a-gold-55) !important;
    color: var(--text-on-card);
    box-shadow: 0 1px 0 var(--paper) inset, 0 10px 28px var(--a-black-35) !important;
}
.import-card.ic .btn-outline-primary { --bs-btn-color: var(--gold-d); --bs-btn-border-color: var(--rule-s); --bs-btn-hover-color: var(--gold-bar-ink); --bs-btn-hover-bg: var(--a-gold-deep-12); }

/* -- Agility Imports -- */
.import-card .card-label {
    font-family: var(--serif);
    font-size: 1.05rem;
    font-weight: 500 !important;
    color: var(--gsl-heading);
}
.ic-head { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--sp-3); }
.ic-title { min-width: 0; }
.ic-title .card-label { line-height: 1.2; }
.ic-sub { font-family: var(--mono); font-size: .7rem; letter-spacing: .04em; color: var(--gsl-txt-muted); margin-top: .15rem; }
.ic-head .badge { align-self: start; }
.ic-figures {
    display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--r-md);
    background: var(--gsl-gold-faint);
}
.ic-k { display: block; font-family: var(--mono); font-size: .62rem; letter-spacing: .16em; text-transform: uppercase; color: var(--gsl-txt-muted); }
.ic-v { display: block; font-family: var(--serif); font-size: 1.05rem; color: var(--gsl-heading); }
.ic-actions { display: flex; gap: var(--sp-2); justify-content: flex-end; margin-top: auto; }
/* Headline numbers (Agility Imports): cream paper like every other card, in BOTH themes. The color
   is in the icon, the number in dark serif. Never green, black or gray (Sunny, 2026-10-01). */
.stat-tile {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4) !important;
    background: var(--card-bg) !important;
    border: 1px solid var(--a-gold-deep-45) !important;
    box-shadow: 0 1px 0 var(--paper) inset, 0 2px 4px var(--a-ink-text-7), 0 10px 24px var(--a-ink-text-14) !important;
}
.stat-tile::before { display: none; }
.stat-tile .section-label { color: var(--gold-d); margin: 0 !important; }
.stat-tile .stat-value { color: var(--text-on-card); font-family: var(--serif); font-size: 1.6rem; line-height: 1.1; }
.stat-tile .icon-chip { width: 2.75rem; height: 2.75rem; border-radius: var(--r-lg); }
.stat-tile .icon-chip .pi { width: 1.5rem; height: 1.5rem; }
.row > :nth-child(4n+1) > .stat-tile .icon-chip { --scr-a: var(--mk-gold-a);    --scr-b: var(--mk-gold-b);    --scr-edge: var(--mk-gold-e);    --scr-ink: var(--gold-bar-ink); }
.row > :nth-child(4n+2) > .stat-tile .icon-chip { --scr-a: var(--mk-royal-a);   --scr-b: var(--mk-royal-b);   --scr-edge: var(--mk-royal-e);   --scr-ink: var(--mk-letter); }
.row > :nth-child(4n+3) > .stat-tile .icon-chip { --scr-a: var(--mk-orange-a);  --scr-b: var(--mk-orange-b);  --scr-edge: var(--mk-orange-e);  --scr-ink: var(--mk-letter); }
.row > :nth-child(4n+4) > .stat-tile .icon-chip { --scr-a: var(--mk-crimson-a); --scr-b: var(--mk-crimson-b); --scr-edge: var(--mk-crimson-e); --scr-ink: var(--mk-letter); }
.stat-tile .icon-chip { background: linear-gradient(180deg, var(--scr-a) 0%, var(--scr-b) 100%); }
/* Cards: the icon carries the color, so the old gold top band goes */
#import-cards .import-card::before { display: none; }
.browse-search {
    position: relative;
    flex: 1 1 22rem;
    max-width: 34rem;
}
.browse-search > .bi-search {
    position: absolute;
    left: .9rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--gold-d);
    pointer-events: none;
}
/* main ... so it outranks the form rule in 15b (main .form-control:not(.form-control-sm)), whose
   padding-left put the text under the search icon. */
main .browse-search .form-control,
.browse-search .form-control {
    height: 2.6rem;
    padding: 0 2.4rem 0 2.5rem;
    background-color: var(--field);
    border: 1px solid var(--a-gold-80);
    border-radius: var(--r-lg);
    color: var(--text-on-card);
    color-scheme: light;
    font-size: .92rem;
}
.browse-search .form-control::placeholder { color: var(--placeholder); }
.browse-search .form-control:focus {
    background-color: var(--field-focus);
    border-color: var(--gold-b);
    box-shadow: 0 0 0 .2rem var(--a-gold-30);
}
.browse-search .form-control::-webkit-search-cancel-button { display: none; }
.browse-search-clear {
    position: absolute;
    right: .45rem;
    top: 50%;
    transform: translateY(-50%);
    width: 1.8rem;
    height: 1.8rem;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: var(--r-md);
    background: transparent;
    color: var(--text-muted-on-card);
    font-size: .8rem;
}
.browse-search-clear:hover { background: var(--a-gold-deep-16); color: var(--ink0); }
.browse-toolbar .btn-outline-secondary {
    --bs-btn-color: var(--gold-b);
    --bs-btn-border-color: var(--a-gold-50);
    --bs-btn-hover-color: var(--cream);
    --bs-btn-hover-bg: var(--a-gold-14);
    --bs-btn-hover-border-color: var(--gold-b);
    height: 2.6rem;
}
/* Browse rows are data, not a list: one line each and tight, like Recent Activity. Wide tables scroll
   sideways (the table carries a min-width) instead of wrapping every name onto three lines. */
.browse-table > tbody > tr > td {
    padding: .45rem .75rem !important;
    white-space: nowrap;
    max-width: var(--table-text-max-width);
    overflow: hidden;
    text-overflow: ellipsis;
    word-break: normal !important;
    font-size: .82rem;
}
.browse-table > thead > tr > th {
    padding: .6rem .75rem !important;
    white-space: nowrap;
}
.browse-table {
    table-layout: auto !important;
    width: max-content !important;
    min-width: 100% !important;
}
/* Agility Browse: the table runs edge to edge in the panel (the header and search bar keep their padding);
   it scrolls sideways in its own container and its gold heading stays put while rows scroll. */
#browse-content { padding: 0 !important; overflow: auto; }
#browse-content .browse-table { margin: 0; border-radius: 0; }
#browse-content .browse-table > thead th { position: sticky; top: 0; z-index: 2; }
main .gsl-form .form-control,
main .gsl-form .form-select,
main .gsl-toolbar .form-control,
main .gsl-toolbar .form-select,
main .gsl-toolbar .browse-search .form-control {
    color-scheme: dark;
    background-color: var(--field-bg-on-dark);
    border: 1px solid var(--field-border-on-dark);
    border-radius: var(--r-md);
    color: var(--field-text-on-dark);
    box-shadow: none;
    --bs-form-select-bg-img: var(--select-caret-on-dark);
}
main .gsl-form .form-control:focus,
main .gsl-form .form-select:focus,
main .gsl-toolbar .form-control:focus,
main .gsl-toolbar .form-select:focus,
main .gsl-toolbar .browse-search .form-control:focus {
    background-color: var(--field-bg-on-dark);
    border-color: var(--gold-b);
    color: var(--field-text-on-dark);
    box-shadow: 0 0 0 2px var(--field-focus-glow-on-dark);
    outline: 2px solid var(--focus-ring);
    outline-offset: 1px;
}
main .gsl-toolbar .browse-search > .bi-search { color: var(--gold-b); }
main .gsl-toolbar .browse-search-clear { color: var(--text-muted-on-frame); }

/* -- Transfers -- */
/* Two-way switch on Transfers (DocuWare | Enable), as the client's own Quote | Order switch: one bordered
   dark bar, the chosen side filled antique gold with dark lettering. */
#tabs.btn-group {
    display: inline-flex;
    gap: 0;
    padding: 0;
    background: var(--onyx-solid);
    border: 1px solid var(--gold-edge);
    border-radius: 8px;
    overflow: hidden;
}
#tabs .btn {
    border: 0 !important;
    border-radius: 0 !important;
    margin: 0;
    padding: .5rem 1.1rem;
    background: transparent !important;
    color: var(--text-muted-on-frame) !important;
    font-family: var(--sans);
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
}
#tabs .btn:hover { color: var(--cream) !important; }
#tabs .btn.active {
    background: var(--gold-b) !important;
    color: var(--gold-bar-ink) !important;
}

/* -- Sign-in -- */
/* One design for both sign-ins: public/login.html (the site's /login) and the downloadable copy's own
   sign-in (portal.js renderSignIn). The photo is set on each page's .hero (an inline background-image), so
   each points at it relative to itself (a url() inside a custom property would resolve against this file). Full-bleed: it covers the portal's header and frame while shown. */
.signin-screen, .signin-screen * { box-sizing: border-box; }
.signin-screen {
    position: fixed;
    inset: 0;
    z-index: 1500;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 40px 24px;
    overflow: hidden;
    font-family: var(--sans);
    font-size: 16px;
    line-height: normal;
    -webkit-font-smoothing: auto;
    -moz-osx-font-smoothing: auto;
    color: var(--cream);
    background: var(--signin-photo-fallback);
}
.signin-screen .hero { position: absolute; inset: 0; z-index: 0; background-position: center; background-size: cover; background-repeat: no-repeat; }
.signin-screen .hero::after { content: ""; position: absolute; inset: 0; background: var(--signin-overlay); }
.signin-screen .wrap { position: relative; z-index: 1; display: grid; justify-items: center; gap: 14px; width: min(var(--signin-content-width), 100%); text-align: center; }
.signin-screen .seal { width: var(--signin-seal-size); height: var(--signin-seal-size); border-radius: 50%; filter: var(--signin-seal-glow); margin: 0 0 6px; vertical-align: baseline; }
.signin-screen .brand { font-family: var(--serif); font-size: var(--signin-wordmark-size); font-weight: 400; line-height: normal; margin: 0; color: var(--signin-text); text-shadow: var(--signin-text-shadow); }
.signin-screen .brand em { color: var(--signin-accent); font-style: italic; }
.signin-screen .eyebrow {
    margin: 0 0 14px;
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .32em;
    text-transform: uppercase;
    color: var(--signin-eyebrow);
    text-shadow: var(--signin-text-shadow);
}
.signin-screen .btn-login {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    min-height: 48px;
    padding: 13px;
    border-radius: 8px;
    border: 1px solid var(--control-metal-to);
    background: var(--signin-button-bg);
    color: var(--control-metal-text);
    font-weight: 600;
    font-size: 15px;
    line-height: normal;
    text-decoration: none;
    box-shadow: var(--signin-button-shadow);
    transition: filter .15s ease, transform .15s ease;
}
.signin-screen .btn-login:hover { filter: brightness(1.05); transform: translateY(-1px); color: var(--control-metal-text); }
.signin-screen .btn-login:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }
.signin-screen .btn-login svg { width: 18px; height: 18px; flex: none; vertical-align: baseline; }
.signin-screen .error,
.signin-screen .note { margin: 2px 0 0; font-size: 13px; line-height: 1.45; text-shadow: var(--signin-text-shadow); }
.signin-screen .error { color: var(--signin-error-text); }
.signin-screen .note { color: var(--signin-text); }
.signin-screen .error[hidden] { display: none; }
/* "Sign in as": the local server's people, shown only against a server on this machine. */
.signin-screen .signin-as { width: 100%; margin-top: 10px; padding-top: 14px; border-top: 1px solid var(--signin-foot-rule); }
.signin-screen .signin-as[hidden] { display: none; }
.signin-screen .signin-as-title { margin: 0 0 8px; font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--signin-eyebrow); text-shadow: var(--signin-text-shadow); }
.signin-screen .signin-as-list { display: grid; gap: 6px; }
.signin-screen .signin-as-person {
    display: flex; justify-content: space-between; align-items: center; gap: 12px; width: 100%;
    padding: 9px 14px; border: 1px solid var(--signin-foot-rule); border-radius: 8px;
    background: var(--a-black-45); color: var(--signin-text); font-size: 14px; text-align: left; cursor: pointer;
}
.signin-screen .signin-as-person:hover { border-color: var(--signin-accent); }
.signin-screen .signin-as-person:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.signin-screen .signin-as-person:disabled { opacity: .6; cursor: wait; }
.signin-screen .signin-as-person .role { font-size: 12px; color: var(--signin-accent); }
.signin-screen .foot {
    width: 100%;
    margin: 26px 0 0;
    padding-top: 16px;
    border-top: 1px solid var(--signin-foot-rule);
    font-family: var(--mono);
    font-size: 10.5px;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--signin-foot-text);
    text-shadow: var(--signin-text-shadow);
}
body.signin-open #portal-chrome { display: none; }
/* The error screen (#error, unknown addresses, no access): the sign-in's look, with the code in place of the wordmark. */
.error-screen .code { font-family: var(--serif); font-size: 56px; font-weight: 400; line-height: 1; margin: 0; color: var(--signin-accent); text-shadow: var(--signin-text-shadow); }
.error-screen .message { margin: 0 0 14px; font-size: 16px; line-height: 1.45; color: var(--signin-text); text-shadow: var(--signin-text-shadow); }
@media (prefers-reduced-motion: reduce) { .signin-screen .btn-login { transition: none; } }
/* Phones: the content sits low over a darker foot of the photo (as nucedar-quote does). */
@media (max-width: 559.98px) {
    .signin-screen { align-items: flex-end; padding: 36px 20px; }
    .signin-screen .hero { background-position: center 30%; }
    .signin-screen .hero::after { background: var(--signin-overlay-phone); }
    .signin-screen .seal { width: 104px; height: 104px; }
}

/* -- Settings -- */
/* Settings: the role picker must fit its longest value (super_admin). */
.role-select {
    min-width: 9.5rem;
}

/* -- Select inspector (owners only) -- */
/* One floating control: a pill in the bottom-right corner, which opens into a card; a bottom sheet on
   phones. Dark ink glass with a thin gold rim: it reads over both the green frame and the cream cards
   (a cream card would vanish against the cream tiles it sits over). */
.inspecting, .inspecting * { cursor: crosshair !important; }
.inspecting .inspector-float, .inspecting .inspector-float * { cursor: auto !important; }
.inspector-box {
    position: fixed;
    z-index: 2000;
    pointer-events: none;
    border: 2px dashed var(--inspector-outline);
    border-radius: var(--r-lg);
}
.inspector-box.is-pinned { border-style: solid; border-color: var(--inspector-pinned); box-shadow: 0 0 0 9999px var(--a-black-15); }
.inspector-box::after {
    content: attr(data-name);
    position: absolute;
    left: -2px;
    top: -1.5rem;
    padding: 1px 6px;
    border-radius: var(--r-sm);
    background: var(--inspector-panel-bg);
    color: var(--inspector-pinned);
    font: 600 .68rem var(--mono);
    letter-spacing: .06em;
    white-space: nowrap;
}
.inspector-pill {
    position: fixed;
    z-index: 2001;
    right: calc(var(--inspector-edge) + env(safe-area-inset-right, 0px));
    bottom: calc(var(--inspector-edge) + env(safe-area-inset-bottom, 0px));
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    min-height: 44px;
    width: var(--inspector-pill-width);
    justify-content: center;
    padding: 0 14px;
    border-radius: 999px;
    border: 1px solid var(--inspector-panel-border);
    background: var(--inspector-panel-bg);
    font: 600 .72rem var(--mono);
    letter-spacing: .16em;
    text-transform: uppercase;
    box-shadow: 0 10px 24px var(--a-black-45);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}
.inspector-pill:hover { border-color: var(--inspector-pinned); }
/* Off: quiet outline, muted. On: gold metal, dark ink. The track and knob say which, as a switch does. */
.inspector-pill { color: var(--text-muted-on-frame); }
.inspector-pill b { font-weight: 700; }
.inspector-track { position: relative; width: 30px; height: 16px; border-radius: 999px; border: 1px solid var(--gold-edge); background: var(--a-black-35); flex: none; }
.inspector-knob { position: absolute; top: 2px; left: 2px; width: 10px; height: 10px; border-radius: 50%; background: var(--text-muted-on-frame); transition: left .15s ease; }
.inspector-pill.is-on { background: var(--control-metal-bg); border-color: var(--control-metal-border); color: var(--control-metal-text); }
.inspector-pill.is-on .inspector-track { background: var(--control-metal-text); border-color: var(--control-metal-text); }
.inspector-pill.is-on .inspector-knob { left: 16px; background: var(--gold-hi); }
@media (prefers-reduced-motion: reduce) {
    .inspector-knob { transition: none; }
}
/* While on: a thin gold frame round the whole window. */
.inspector-frame { position: fixed; inset: 0; z-index: 1999; pointer-events: none; box-shadow: inset 0 0 0 3px var(--inspector-pinned); }
.inspector-hint-float {
    position: fixed;
    z-index: 2001;
    right: calc(var(--inspector-edge) + env(safe-area-inset-right, 0px));
    right: calc(var(--inspector-edge) + var(--inspector-pill-width) + 8px + env(safe-area-inset-right, 0px));
    bottom: calc(var(--inspector-edge) + env(safe-area-inset-bottom, 0px));
    max-width: min(18rem, calc(100vw - var(--inspector-pill-width) - 40px));
    padding: 6px 10px;
    border-radius: var(--r-md);
    background: var(--inspector-panel-bg);
    border: 1px solid var(--gold-line);
    color: var(--inspector-panel-text);
    font-size: .78rem;
}
.inspector-card {
    position: fixed;
    z-index: 2001;
    width: var(--inspector-card-width);
    max-height: 70vh;
    overflow: auto;
    padding: 0 var(--sp-4) var(--sp-4);
    border: 1px solid var(--inspector-panel-border);
    border-radius: var(--r-xl);
    background: var(--inspector-panel-bg);
    color: var(--inspector-panel-text);
    box-shadow: 0 18px 40px var(--a-black-45);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
}
.inspector-card.is-sheet {
    left: 0 !important;
    right: 0;
    top: auto !important;
    bottom: calc(var(--inspector-edge) + 44px + 8px + env(safe-area-inset-bottom, 0px));   /* sits above the switch */
    width: auto;
    max-height: 55vh;
    margin: 0 8px;
    border-radius: var(--r-xl);
}
.inspector-head {
    position: sticky;
    top: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin: 0 calc(-1 * var(--sp-4)) var(--sp-2);
    padding: var(--sp-2) var(--sp-4);
    background: var(--inspector-panel-bg);
    border-bottom: 1px solid var(--gold-line);
    cursor: move !important;
    touch-action: none;
}
.inspector-card.is-sheet .inspector-head { cursor: auto !important; }
.inspector-eyebrow { font: 600 .66rem var(--mono); letter-spacing: .2em; text-transform: uppercase; color: var(--highlight-text-on-frame); }
.inspector-icon { border: 0; background: none; color: var(--text-muted-on-frame); font-size: 1.3rem; line-height: 1; min-width: 36px; min-height: 36px; border-radius: var(--r-md); }
.inspector-icon:hover { color: var(--inspector-pinned); }
.inspector-hint { margin: var(--sp-2) 0 var(--sp-3); color: var(--text-muted-on-frame); font-size: .85rem; }
.inspector-path { margin: 0 0 var(--sp-1); font: 600 .85rem var(--mono); color: var(--inspector-pinned); word-break: break-word; }
.inspector-label { margin: 0 0 var(--sp-3); color: var(--text-muted-on-frame); font-size: .85rem; }
.inspector-tokens { list-style: none; margin: 0 0 var(--sp-3); padding: 0; display: grid; gap: 6px; }
.inspector-tokens li { display: grid; grid-template-columns: 18px auto 1fr; align-items: center; gap: 8px; font-size: .78rem; }
.inspector-tokens code { color: var(--inspector-panel-text); }
.inspector-value { color: var(--text-muted-on-frame); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--mono); }
.inspector-swatch { width: 18px; height: 18px; border-radius: var(--r-sm); box-shadow: 0 0 0 1px var(--gold-edge); }
.inspector-swatch.is-empty { box-shadow: 0 0 0 1px var(--gold-line); }
.inspector-none { color: var(--text-muted-on-frame); }
.inspector-actions { display: flex; gap: var(--sp-2); justify-content: flex-end; flex-wrap: wrap; }

/* == 6. Utilities == */
/* Small single-purpose helpers. */

/* -- Utilities -- */
.col-nowrap { white-space: nowrap; }
.col-min-xs { min-width: 5rem; }
.col-min-sm { min-width: 7rem; }
.col-min-md { min-width: 9rem; }
.col-min-lg { min-width: 16rem; }
.fit-content {
    width: fit-content;
}
.min-w-0 {
    min-width: 0;
}
.sr-only {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

/* -- Reach: who an app opens to, and what a person is assigned -- */
/* One grammar for the whole decision: everything that reaches somebody is a
   chip, whether it is a group, a place or a name. The panel answers first and
   offers the controls under the answer. */
.reach {
    border: 1px solid var(--rule);
    border-radius: var(--r-lg);
    background: var(--paper);
    overflow: hidden;
}
.reach-say {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-3) var(--sp-2);
    border-bottom: 1px solid var(--rule);
    background: var(--table-row-even);
}
.reach-say-key {
    font-family: var(--mono);
    font-size: .62rem;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--gold-d);
}
.reach-say-val {
    font-family: var(--serif);
    font-size: 1rem;
    line-height: 1.3;
    color: var(--text-on-card);
}
.reach-say-val .none {
    font-family: var(--sans);
    font-size: .85rem;
    font-style: italic;
    color: var(--ltx2);
}

/* "Everyone signed in" is the question the rest of the panel only matters
   after, so it gets its own band rather than a place in the list. */
.reach-all {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    width: 100%;
    padding: var(--sp-2) var(--sp-3);
    border: 0;
    border-bottom: 1px solid var(--rule);
    background: transparent;
    text-align: left;
    color: var(--text-on-card);
    font-size: .9rem;
}
.reach-all:hover { background: var(--a-gold-18); }
.reach-all .mark {
    flex: none;
    width: 1.05rem;
    height: 1.05rem;
    border: 1px solid var(--field-border-on-cream);
    border-radius: var(--r-sm);
    background: var(--field-bg-on-cream);
}
.reach-all[aria-pressed="true"] { background: var(--a-gold-18); }
.reach-all[aria-pressed="true"] .mark {
    border-color: var(--gold-d);
    background: var(--gold-bar);
    box-shadow: inset 0 0 0 2px var(--paper-cream);
}
.reach-all .says { color: var(--ltx2); font-size: .8rem; }
.reach-all:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }

.reach-sec { padding: var(--sp-3); border-bottom: 1px solid var(--rule); }
.reach-sec:last-child { border-bottom: 0; }
.reach-sec > .gsl-label { color: var(--gold-d); margin-bottom: var(--sp-2); }
.reach-row { display: flex; flex-wrap: wrap; gap: var(--sp-1); }

/* Everyone covers the rest. The sections stay legible and say why they are
   quiet, rather than graying into something that reads as broken. */
.reach.covered .reach-sec { background: var(--table-stripe); }
.reach.covered .chip { opacity: .55; }
.reach-covered-says {
    padding: var(--sp-2) var(--sp-3);
    border-top: 1px solid var(--rule);
    background: var(--table-stripe);
    color: var(--ltx2);
    font-size: .8rem;
}

/* -- Chips -- */
.chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    padding: 3px 10px;
    border: 1px solid var(--field-border-on-cream);
    border-radius: 999px;
    background: var(--field-bg-on-cream);
    color: var(--field-text-on-cream);
    font-size: .82rem;
    line-height: 1.5;
}
button.chip { cursor: pointer; }
button.chip:hover { border-color: var(--gold); background: var(--paper); }
button.chip:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
.chip.on {
    border-color: var(--gold-d);
    background: var(--gold-bar);
    color: var(--gold-bar-ink);
    font-weight: 600;
}
.chip.on:hover { border-color: var(--gold-d); background: var(--gold-bar); }
.chip .tick { font-size: .7rem; opacity: .85; }
.chip .sub { color: var(--ltx2); font-size: .74rem; font-weight: 400; }
.chip.on .sub { color: var(--gold-d); }
/* A chip somebody else's decision put there: no cross, because it comes off
   where it was set. */
.chip.fixed { border-style: dashed; background: transparent; }
.chip-x {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1rem;
    height: 1rem;
    margin-right: -4px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: inherit;
    font-size: .9rem;
    line-height: 1;
    opacity: .6;
}
.chip-x:hover { opacity: 1; background: rgba(0, 0, 0, .12); }
.chip-x:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
.chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* -- Picker: chosen above, a search below, answers in a sheet under the box -- */
.pick-tags { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.pick-tags:empty { display: none; }
.pick-none { color: var(--ltx2); font-size: .82rem; font-style: italic; }
.pick-box { position: relative; }
.pick-find { margin-top: var(--sp-2); }
.pick-hits {
    margin-top: var(--sp-1);
    padding: var(--sp-1);
    border: 1px solid var(--gold);
    border-radius: var(--r-md);
    background: var(--paper);
    max-height: 13rem;
    overflow-y: auto;
}
.pick-hits:empty { display: none; }
.pick-take {
    display: flex;
    align-items: baseline;
    gap: var(--sp-2);
    width: 100%;
    padding: 5px var(--sp-2);
    border: 0;
    border-radius: var(--r-sm);
    background: transparent;
    text-align: left;
    color: var(--text-on-card);
    font-size: .85rem;
}
.pick-take:hover,
.pick-take:focus-visible { background: var(--a-gold-18); outline: none; }
.pick-take .sub { color: var(--ltx2); font-size: .76rem; font-family: var(--mono); }
.pick-miss { padding: 5px var(--sp-2); color: var(--ltx2); font-size: .82rem; }

/* One person, standing in place of the settings tabs: who they are and the role
   they hold across the top, the two things that hand out apps side by side, and
   the reading of both underneath. The cards are cream so the controls that write
   are plainly separate from the table that only reports. */
.person-crumb {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin-bottom: var(--sp-4);
}
.person-crumb-sep { color: var(--ltx2); }
.person-crumb-name {
    font-family: var(--mono);
    font-size: .78rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--text-muted-on-frame);
}
.person-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--sp-5);
    padding-bottom: var(--sp-4);
    border-bottom: 1px solid var(--gsl-border);
}
.person-name {
    font-family: var(--serif);
    font-size: 2.2rem;
    line-height: 1.1;
    margin: var(--sp-2) 0 6px;
}
.person-mail {
    color: var(--text-muted-on-frame);
    font-family: var(--mono);
    font-size: .82rem;
}
.person-role {
    flex: 0 0 auto;
    min-width: 15rem;
    max-width: 20rem;
}
.person-role .gsl-label { display: block; margin-bottom: 6px; }
.person-says {
    margin-top: 6px;
    color: var(--text-muted-on-frame);
    font-size: .8rem;
    line-height: 1.45;
    max-width: 34rem;
}
.person-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: var(--sp-4);
    margin: var(--sp-4) 0;
}
.person-card {
    background: var(--cream);
    border: 1px solid var(--rule);
    border-radius: var(--r-lg);
    padding: var(--sp-4);
    color: var(--ltx);
}
.person-card h3 {
    font-family: var(--serif);
    font-size: 1.25rem;
    margin: 0 0 4px;
    color: var(--ltx);
}
.person-card-says {
    margin: 0 0 var(--sp-3);
    color: var(--ltx2);
    font-size: .82rem;
    line-height: 1.45;
}
/* The heading, a rule that takes up the slack, and the count at the far end. */
.person-rule {
    display: flex;
    align-items: baseline;
    gap: var(--sp-3);
    margin: var(--sp-5) 0 var(--sp-2);
}
.person-rule h3 {
    font-family: var(--serif);
    font-size: 1.5rem;
    margin: 0;
}
.person-rule-line {
    flex: 1 1 auto;
    height: 1px;
    background: var(--gsl-border);
}
.person-rule-count {
    flex: 0 0 auto;
    color: var(--text-muted-on-frame);
    font-size: .82rem;
}
.person-inside {
    font-size: .82rem;
    white-space: nowrap;
}
@media (max-width: 575.98px) {
    .person-name { font-size: 1.6rem; }
    .person-role { min-width: 100%; max-width: none; }
    .person-rule h3 { font-size: 1.2rem; }
}

/* The same chip worn by a checkbox, so a group reads the same wherever it is
   chosen. The box itself is off screen and the label carries the state. */
/* `main label` is the page's micro-label; a chip wearing a label resets it. */
main label.chip-pick {
    cursor: pointer;
    margin: 0;
    font-family: var(--sans);
    font-size: .82rem;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
    color: var(--field-text-on-cream);
}
.chip-pick input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}
.chip-pick .tick { opacity: 0; }
.chip-pick:hover { border-color: var(--gold); background: var(--paper); }
.chip-pick:has(input:checked) {
    border-color: var(--gold-d);
    background: var(--gold-bar);
    color: var(--gold-bar-ink);
    font-weight: 600;
}
.chip-pick:has(input:checked) .tick { opacity: .85; }
.chip-pick:has(input:focus-visible) { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* A count standing in for the rest of the bubbles: the row stays a row. */
.chip.more {
    border-style: dotted;
    background: transparent;
    color: var(--ltx2);
    font-family: var(--mono);
    font-size: .74rem;
}

/* A hit that is already chosen says so where it is read, and the same click
   takes it off again. */
.pick-mark {
    flex: none;
    width: .9rem;
    color: var(--gold-d);
    font-size: .74rem;
}
.pick-take.on { color: var(--gold-d); font-weight: 600; }

/* The exception worth seeing from across the table: this app reaches this
   person because somebody named them, and nothing else would. */
.named-only {
    color: #5A1A1C;
    font-family: var(--mono);
    font-size: .72rem;
    letter-spacing: .02em;
}

/* A field the sign-in does not supply: its name, then what it holds. */
.person-meta-label {
    flex: none;
    width: 8.5rem;
    margin: 0;
    text-align: right;
}

/* A table that would otherwise push what follows off the screen stops instead and
   scrolls inside its panel; the heading bar is already sticky, so it stays put. */
.table-capped { max-height: 24rem; overflow-y: auto; }
/* A table that runs its full length instead: the page scrolls, and the heading row stays at the top
   of the window, under the fixed header, while the rows pass beneath it. On a narrow screen the
   panel scrolls sideways as any other table does (and the heading then scrolls with it). */
.table-flow { overflow: visible; }
.table-flow .table-head th { top: var(--header-h); }
@media (max-width: 991.98px) {
    .table-flow { overflow-x: auto; -webkit-overflow-scrolling: touch; }
    .table-flow .table-head th { position: static; }
}

/* -- Add a person -- */
.add-person-head {
    background: var(--gold-bar);
    border-bottom: 1px solid var(--gold-bar-edge);
    padding: 1.15rem 1.5rem;
}
.add-person-title {
    font-family: var(--serif);
    font-size: 1.5rem;
    font-weight: 600;
    color: var(--gold-bar-ink);
    margin: 0;
}
.add-person-head .btn-close { opacity: .7; }
.add-person-body { padding: 1.5rem; display: grid; gap: 1.5rem; }
.add-person-top {
    display: grid;
    gap: 1.25rem;
    grid-template-columns: 1.6fr 1fr;
    align-items: start;
}
.add-person-says {
    margin-top: .4rem;
    font-size: .78rem;
    color: var(--gsl-txt-muted);
}
.add-person-split {
    display: grid;
    gap: 1.25rem;
    grid-template-columns: 1fr 1fr;
    align-items: start;
}
.add-teams { display: grid; gap: .75rem; }
.add-teams-head {
    font-family: var(--serif);
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--gsl-heading);
    margin: 0;
}
.add-teams-head span {
    font-family: var(--sans);
    font-size: .82rem;
    font-weight: 400;
    color: var(--gsl-txt-muted);
}
.team-ticks { display: grid; gap: .5rem; }
/* `main label` is the page's micro-label; a tick row wearing a label resets it. */
main label.team-tick,
.team-tick {
    font-family: var(--sans);
    font-size: .88rem;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
    color: var(--gsl-txt);
    margin: 0;
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: .75rem;
    padding: .7rem .9rem;
    border: 1px solid var(--gsl-border);
    border-radius: var(--r-md);
    background: var(--gsl-surface);
    cursor: pointer;
}
.team-tick input {
    appearance: none;
    width: 1.15rem;
    height: 1.15rem;
    margin: 0;
    border: 1px solid var(--gsl-border-strong);
    border-radius: 4px;
    background: var(--gsl-surface);
    grid-area: 1 / 1;
}
.team-tick .tick {
    grid-area: 1 / 1;
    justify-self: center;
    font-size: .8rem;
    line-height: 1;
    color: var(--gold-bar-ink);
    opacity: 0;
    pointer-events: none;
}
.team-tick:hover { border-color: var(--gsl-gold); }
.team-tick.is-on {
    background: var(--gold-tint);
    border-color: var(--gsl-gold);
}
.team-tick.is-on input { background: var(--gold); border-color: var(--gold-d); }
.team-tick.is-on .tick { opacity: 1; }
.team-tick:has(input:focus-visible) { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.team-tick-body { display: grid; gap: .1rem; min-width: 0; }
.team-tick-name { font-weight: 600; color: var(--gsl-heading); }
.team-tick-gets {
    font-size: .8rem;
    color: var(--gsl-txt-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.team-tick-count {
    font-size: .8rem;
    color: var(--gsl-txt-muted);
    white-space: nowrap;
}
.add-sum {
    background: var(--ink1);
    border: 1px solid var(--gold-line);
    border-radius: var(--r-md);
    padding: 1.1rem 1.15rem;
    display: grid;
    gap: .75rem;
    align-content: start;
}
.add-sum-eyebrow {
    font: 600 10.5px var(--mono);
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--gold-b);
    margin: 0;
}
.add-sum-count {
    font-family: var(--serif);
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--cream);
    margin: 0;
}
.add-sum-list { display: grid; gap: .5rem; }
.add-sum-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .75rem;
    padding: .65rem .8rem;
    border: 1px solid var(--gold-line);
    border-radius: var(--r-md);
    background: var(--a-gold-10);
}
.add-sum-body { display: grid; gap: .1rem; min-width: 0; }
.add-sum-app { font-weight: 600; color: var(--cream); }
.add-sum-cat { font-size: .8rem; color: var(--text-muted-on-frame); }
.add-sum-why {
    font-size: .8rem;
    color: var(--gold-b);
    white-space: nowrap;
}
.add-sum-none,
.add-sum-note {
    font-size: .8rem;
    color: var(--text-muted-on-frame);
    margin: 0;
}
.add-sum-none { font-style: italic; }
.add-person-foot {
    padding: 1rem 1.5rem;
    border-top: 1px solid var(--gsl-border);
}
.add-person-cancel {
    font-family: var(--mono);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
}

@media (max-width: 767.98px) {
    .add-person-top,
    .add-person-split { grid-template-columns: 1fr; }
    .add-person-body { padding: 1.15rem; }
}

/* The form sits between the content and the body, so the scroll chain a
   scrollable modal sets up has to pass through it or the footer is pushed off. */
.add-person > form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}
.add-person-body { overflow-y: auto; min-height: 0; }
.add-person-foot { flex: 0 0 auto; }

.person-meta-kind {
    font: 600 10.5px var(--mono);
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--gsl-accent);
    margin-top: .5rem;
}
.person-meta-kind:first-child { margin-top: 0; }
.person-meta-add {
    display: grid;
    gap: .5rem;
    grid-template-columns: 8rem 11rem 1fr auto;
    align-items: center;
}
@media (max-width: 575.98px) {
    .person-meta-add { grid-template-columns: 1fr 1fr; }
    .person-meta-add [name="value"] { grid-column: 1 / -1; }
}
