/* The customer portal's stylesheet.
 *
 * THIS WAS AN INLINE <style> BLOCK IN base.html UNTIL 2026-09-05, AND IT WAS BLOCKED IN PRODUCTION.
 * The Caddyfile serves `style-src 'self'` with no 'unsafe-inline', which is correct and stays. A page
 * whose entire stylesheet is inline is therefore a page with no stylesheet at all, and that is exactly
 * what a customer arriving from their licence e-mail was getting: Times New Roman on a white ground,
 * 8px body margin, no layout.
 *
 * MEASURED before the move, in a real browser through the real proxy:
 *   document.styleSheets.length ... 0     (one <style> tag present, zero applied)
 *   body font-family ............. "Times New Roman"
 *   body background .............. rgba(0, 0, 0, 0)
 *   .wrap max-width .............. none   (44rem intended)
 * plus two console errors naming the directive that blocked it.
 *
 * It went unnoticed because local development runs DJANGO_DEBUG=1 without the proxy, so the header that
 * breaks the page is the one header no developer ever sees. ops/edge_test.py now asks the question from
 * OUTSIDE the edge, which is the only place it is askable.
 *
 * SO: no rule may move back into a template, and no element may carry a style= attribute. A CSP hash
 * cannot rescue a style attribute at all without 'unsafe-hashes', and the utilities at the bottom of
 * this file exist precisely so nobody needs one.
 *
 * AND THIS IS THE ONLY STYLESHEET THE PORTAL MAY LINK. ops/edge_test.py asserts the served page carries
 * exactly one <link rel="stylesheet">, matched with `rel` BEFORE `href`, in double quotes. A second
 * sheet for print, for fonts, or for one page fails the gate. Everything lives here.
 *
 * ------------------------------------------------------------------------------------------------
 * THE ACCOUNT IS A TOOL, NOT A BRAND SURFACE. 2026-09-06, and this reverses a decision taken earlier
 * the same day, so the reversal is written here rather than left for somebody to find as a
 * contradiction.
 *
 * The first version of this rewrite copied the marketing site exactly: the deck's near black ground,
 * the phosphor labels, 2px corners, uppercase letterspaced everything. The reasoning was "one product,
 * one look", and the controller looked at it and asked for Apple and Stripe instead. They are right,
 * and the argument is about what each surface is FOR rather than about taste.
 *
 * The site is atmosphere. It is a night airfield, it is meant to be felt, and somebody reads it once
 * before deciding. THIS page is where a person manages a licence, reads what they were charged, moves
 * an installation to a new machine and closes an account. It is scanned, not felt, and it is opened
 * when something needs doing or has gone wrong. A dark cinematic ground makes every one of those jobs
 * slower. Stripe's dashboard, Linear's settings and Apple's account pages are all light and quiet for
 * the same reason, sitting behind marketing that is not.
 *
 * WHAT CARRIES THE BRAND ACROSS instead of the palette: the same three typefaces, the same mark, and
 * the orange, which appears exactly once per page and only in the mark. A near black primary button is
 * deliberate rather than a compromise; on a white ground an orange one shouts, and restraint is most
 * of what this look is.
 *
 * LIGHT ONLY, and no prefers-color-scheme block. Same reasoning as the site's single theme, pointed
 * the other way: a page that changes its ground depending on the reader's operating system is two
 * designs, and only one of them was drawn.
 */

/* ------------------------------------------------------------------------------------------------
 * TYPEFACES. Latin subset, copied from server/site/assets/fonts/, because `default-src 'self'` means
 * this host cannot fetch them from the site's origin and `font-src` falls back to the same directive,
 * which does not include `data:`. Five faces, 128 KB, in fonts/ beside this file.
 *
 * WhiteNoise's ManifestStaticFilesStorage rewrites the url() below to hashed names at collectstatic,
 * which is also why a missing face breaks the image build rather than the page.
 */
@font-face{font-family:'Barlow';font-style:normal;font-weight:300;font-display:optional;src:url("fonts/barlow-300.de218f435ec7.woff2") format('woff2')}
@font-face{font-family:'Barlow';font-style:normal;font-weight:400;font-display:optional;src:url("fonts/barlow-400.81419bf5abb5.woff2") format('woff2')}
@font-face{font-family:'Barlow';font-style:normal;font-weight:600;font-display:optional;src:url("fonts/barlow-600.a1e2a2d7d4c0.woff2") format('woff2')}
@font-face{font-family:'Barlow Condensed';font-style:normal;font-weight:500;font-display:optional;src:url("fonts/barlow-condensed-500.24f826a7cf9c.woff2") format('woff2')}
@font-face{font-family:'Barlow Condensed';font-style:normal;font-weight:600;font-display:optional;src:url("fonts/barlow-condensed-600.ba4513495282.woff2") format('woff2')}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:500;font-display:optional;src:url("fonts/jetbrains-mono-500.b636a65da4f0.woff2") format('woff2')}
/* font-display IS `optional` AND NOT `swap`, and the pages preload every face above. The full
 * reasoning is at the top of site/assets/site.css, which made the same change on the same day for the
 * same report: `swap` has a zero length block period, so a hard refresh paints in the machine's own
 * sans and then snaps to Barlow, which is what the controller saw. `optional` makes that swap
 * impossible rather than unlikely; the preloads are what make sure the real font is what gets
 * committed. Neither half works without the other. */

/* ------------------------------------------------------------------------------------------------
 * TOKENS
 *
 * One ground, one ink, and a card, which is most of this look. The page is darker than the cards and
 * the cards are pure white, so a card reads as raised without needing a heavy shadow to say so; that
 * grouping is the pattern Apple's settings and Stripe's dashboard both use, and it does more work
 * than any border. The ground was a very light grey until 2026-09-09 and is now a warm cream; the
 * relationship it is here to describe is the same either way, which is why this paragraph does not
 * name a colour.
 *
 * SEMANTIC COLOUR IS SEPARATE FROM THE BRAND. Green, amber and red say what state a licence is in.
 * Orange says Airside. They are never swapped, and orange never means "good".
 */
/* THE GROUND IS WARM, NOT GREY, AND THE FOUR TOKENS BELOW IT MOVED WITH IT. Controller, 2026-09-09:
 * "account.airsideatc bolumunun arkaplani full beyaz degilde #EEDFBE rengine benzer yap", and then,
 * looking at #EEDFBE on the real page: "cok kotu oldu ya renk daha acik renk olsun baya". So the hue
 * is theirs and the strength is the correction: the same cream, taken most of the way to white.
 *
 * FOUR TOKENS AND NOT ONE, because a warm ground under a cool palette is not the same design with a
 * different background - it is two designs. The hairlines and the sunk field read blue-grey against
 * cream however light it is, and the captions lose contrast. Both are measured below rather than
 * judged.
 *
 * THE CAPTION COLOUR IS A CONTRAST FIX AND NOT A TASTE ONE. --ink-3 is the colour of the masthead
 * links, the footer, every section label and every .muted line, and most of those sit DIRECTLY on the
 * ground rather than inside a card. WCAG contrast, computed against each ground:
 *
 *     #8A8A94 on #F6F6F7 (the grey it used to be) .... 3.16:1   already under the 4.5:1 AA floor
 *     #8A8A94 on #FAF6EC (this ground) ............... 3.17:1   no better, and no worse
 *     #665E4E on #FAF6EC ............................. 5.94:1   passes
 *     #665E4E on #FFFFFF (inside a card) ............. 6.41:1   passes
 *
 * THE SECOND ROW IS THE ONE WORTH READING TWICE, because it is not what was expected. At #EEDFBE the
 * old caption colour fell to 2.59:1 and the contrast fix was forced by the ground; at this strength
 * the ground barely moves it at all. The fix stayed anyway, and this is the honest reason: the row
 * above it was already failing before anybody touched a colour, so leaving it would have been
 * choosing to ship a known failure because the excuse for fixing it had gone away.
 *
 * So the ground change did not create this problem, it made an existing one impossible to leave. The
 * new value is the same warmth as the ground rather than a neutral grey, which is what keeps the page
 * reading as one surface.
 *
 * THE CARD STAYS PURE WHITE, deliberately, and this is the token that suffers most from a light
 * ground: the note below says a card reads as raised because the ground is darker than it is, and the
 * lighter the ground goes the less of that there is to spend. It is why the hairline below matters
 * more here than it did at #EEDFBE - at this strength the border is doing about as much of the
 * separating as the fill is.
 */
:root{
  --page:#FAF6EC;        /* the ground the cards sit on */
  --card:#FFFFFF;
  --sunk:#F4EFE2;        /* an inset field or a code chip */

  --ink:#18181B;         /* text */
  --ink-2:#52525B;       /* secondary text, still comfortably readable */
  --ink-3:#665E4E;       /* labels and captions; 5.94:1 on the ground, see the note above */

  --line:#E5DECD;        /* hairline */
  --line-2:#F0EADD;      /* a divider INSIDE a card, lighter than its border */

  --brand:#FF6B1A;       /* Theme.Orange. The mark, and nothing else */
  --ok:#137A45;
  --warn:#8A5A00;
  --bad:#B4231C;
  --ok-bg:#E9F6EF;
  --warn-bg:#FDF4E3;
  --bad-bg:#FCECEA;
  /* FIVE MORE THAT WERE LITERALS until a dark ground existed (2026-09-26): on midnight or wine a white
   * label on a button filled with --ink would sit on a light fill, and a light drop zone would glare. */
  --on-ink:#FFFFFF;      /* the label on a button filled with --ink */
  --ink-hover:#2C2C33;   /* that button, hovered */
  --line-hover:#D2D2D8;  /* a field's border, hovered */
  --drop:#EFE8D8;        /* the drop zone while a file is held over it */
  --placeholder:#A8A29A;

  --ui:"Barlow",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --sign:"Barlow Condensed","Barlow",-apple-system,"Segoe UI",sans-serif;
  --mono:"JetBrains Mono","Cascadia Mono",ui-monospace,Consolas,monospace;

  --r:12px;              /* a card */
  --r-s:8px;             /* a control */

  /* Two shadows, both nearly invisible on their own. A card that announces itself with a shadow is a
   * card from a template; these are here so an edge does not disappear on a low contrast display. */
  --shadow:0 1px 2px rgba(24,24,27,.04), 0 1px 3px rgba(24,24,27,.06);
  --shadow-lift:0 1px 2px rgba(24,24,27,.05), 0 4px 12px rgba(24,24,27,.07);

  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:36px; --s7:56px; --s8:80px;
  --ease:cubic-bezier(.16,1,.3,1);
  --quick:150ms;
}

/* ------------------------------------------------------------------------------------------------
 * A SUPPORTER'S GROUND. Controller, 2026-09-24: "hesap sayfası farklı görünmeli supporter account vs
 * yazmalı arkaplan rengi de değişmeli 3 farklı renk olsun airside ruhuna felsefesine uygun". Three, and
 * each is a colour the airfield already uses to tell a pilot something: the blue of a taxiway's edge
 * lights, the green of its centreline lights, the yellow of a direction sign. The supporter picks one
 * on the account page and every account page wears it; base.html prints the class, only for a
 * supporter, and the first is worn until they pick.
 *
 * AND SINCE 2026-09-26 ("default renk yok ... 3-4 renk ekle çekici ... koyu da ekle midnight purple gibi
 * wine gibi"): Default, the cream everybody else sees, which prints no class at all; the orange of a
 * windsock and the grey of the runway; and two for the night, midnight purple and wine. A DARK GROUND IS
 * A WHOLE PALETTE, not five tokens: the card, the ink, the status colours and the five literals above
 * turn with it, so the page stays one design rather than a light page on a dark floor.
 *
 * FIVE TOKENS EACH AND NOT ONE, for the reason the cream's note above gives: a new ground under the old
 * hairlines, sunk field and captions is two designs. The card stays white on all three, so a card still
 * reads as raised, and by a little more than on the cream (1.11 to 1.12 against 1.08).
 *
 * MEASURED, NOT JUDGED, like the cream. WCAG contrast of --ink-3 against each surface it sits on:
 *
 *                  on the ground   on a sunk field   in a card
 *     cream            5.94             5.58            6.41      everybody else, unchanged
 *     taxiway          6.44             5.97            7.24
 *     centreline       6.47             5.96            7.19
 *     sign             6.90             6.27            7.74
 *     windsock         7.28             6.51            8.28
 *     runway           6.68             6.04            7.63
 *     midnight         8.09             8.70            7.15      its own card, #272042
 *     wine             8.65             9.27            7.76      its own card, #3A1922
 *
 * On the two dark grounds a button's label keeps 15:1 on its fill, and each status colour 7:1 on its own
 * tinted field.
 *
 * ops/client_test.py (T-SUPPORTER-GROUND-CSS) recomputes these from this file and holds each to 4.5:1,
 * and the three names are the ones Customer.Ground stores.
 */
body.ground-taxiway{--page:#EDF2FA;--sunk:#E2EAF5;--line:#D0DBEA;--line-2:#E6EDF6;--ink-3:#4B5869}
body.ground-centreline{--page:#ECF5EF;--sunk:#E0EDE4;--line:#CCE0D3;--line-2:#E4EFE8;--ink-3:#485C4F}
body.ground-sign{--page:#FBF2D0;--sunk:#F4E7BC;--line:#E6D69F;--line-2:#F3E9C6;--ink-3:#5C5234}
body.ground-windsock{--page:#FCEEE2;--sunk:#F7E0CD;--line:#EDCDB4;--line-2:#F6E4D5;--ink-3:#6A4632}
body.ground-runway{--page:#EEF0F2;--sunk:#E2E5E9;--line:#D2D6DC;--line-2:#E7E9EC;--ink-3:#4D5460}
body.ground-midnight{color-scheme:dark;--page:#1C1633;--card:#272042;--sunk:#140F26;--ink:#F2EEFA;--ink-2:#CFC7E4;
  --ink-3:#B6ACD0;--line:#3C3260;--line-2:#312852;--ok:#7ED9A6;--warn:#F3C865;--bad:#FF9A90;--ok-bg:#173A2C;
  --warn-bg:#3A2F12;--bad-bg:#431E26;--on-ink:#1C1633;--ink-hover:#DCD4EE;--line-hover:#4E4378;--drop:#312852;
  --placeholder:#8E84A8}
body.ground-wine{color-scheme:dark;--page:#2B1219;--card:#3A1922;--sunk:#200C12;--ink:#FBF0F2;--ink-2:#E6CCD2;
  --ink-3:#D0AEB6;--line:#5A2A37;--line-2:#4A222D;--ok:#7ED9A6;--warn:#F3C865;--bad:#FFA095;--ok-bg:#173A2C;
  --warn-bg:#3A2F12;--bad-bg:#4D1D25;--on-ink:#2B1219;--ink-hover:#EFDCE0;--line-hover:#6E3545;--drop:#4A222D;
  --placeholder:#A88790}
/* THE MARK IS AN IMAGE DRAWN IN INK, so on a dark ground it would vanish: turned to the light ink instead. */
body.ground-midnight .mark,body.ground-wine .mark{filter:invert(1)}

*{box-sizing:border-box}

/* Every digit that sits in a column. A number that is not tabular changes width and shoves whatever is
 * beside it, which here means a machine fingerprint next to a date. */
.key,.mono,code,.row-val,.fact dd{font-variant-numeric:tabular-nums}

[hidden]{display:none!important}

body{
  margin:0;
  background:var(--page);
  color:var(--ink);
  font:400 16px/1.6 var(--ui);
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}

/* ------------------------------------------------------------------------------------------------
 * SHELL, SINCE 2026-09-26: A BAR ACROSS THE TOP, A RAIL BESIDE THE PAGE, AND THE CONTENT TAKES THE REST
 * (controller: "account sayfası ortalanmış yav yani çerçeve sanki 9:16 gibi tüm sayfayı kullanmıyoz daha güzel hale
 * getirsene daha modern UI UX").
 *
 * ~~Narrow, centred, and generous at the top~~: ONE 44rem column held everything, the account's six pages included,
 * so a wide screen was two empty margins around a strip. The measure that argument was about still holds, and still
 * where it always did: a paragraph stops at 62ch and a row keeps its control beside its label. What changed is that the
 * page no longer squeezes everything else to the width of a paragraph.
 *
 * BEFORE SIGN IN THERE IS NO RAIL, and the single narrow column stays: one form, read once, centred on purpose.
 */
/* THE BAR IS A FLOATING BOX (controller, 2026-09-26: "boydan boya olmasın logo ve sign out a kadar olsun ve yuvarlağımsı
 * olsun ve üsttende boşluk olsun kutu gibi"): as wide as the page's content, from the mark to Sign out, rounded, with room
 * above it, and it stays there as the page moves under it. The strip it floats in is transparent; the box is glass where
 * the browser can blur ("sabit buzlu cam", then "çok beyaz ... biraz daha şeffaf": 42 per cent of the card colour and a
 * 20px blur, so a card or a line of text passing under it shows as a soft shape), and the card colour, solid, where not.
 * Before sign in the page is one narrow column, and the box is as narrow as it. */
.bar{position:sticky;top:0;z-index:20;padding:var(--s3) var(--s5) 0}
.bar-in{
  max-width:calc(76rem - 2 * var(--s5));margin:0 auto;height:56px;padding:0 10px 0 var(--s4);
  display:flex;align-items:center;gap:var(--s3);border-radius:16px;
}
.bar-narrow .bar-in{max-width:calc(44rem - 2 * var(--s5))}
.mark{display:block;width:20px;height:20px}
/* THE LOGO IS A LINK TO THE SITE (2026-09-26): the mark and the name together, no underline, the same look as before. */
.brand{display:flex;align-items:center;gap:var(--s3);text-decoration:none;color:inherit}
.brand:hover .wordmark{color:var(--ink-2)}
.brand:focus-visible{outline:2px solid var(--ink);outline-offset:4px;border-radius:6px}
.wordmark{
  font-family:var(--sign);font-weight:600;font-size:17px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--ink);
}
.bar-sep{width:1px;height:18px;background:var(--line);margin:0 var(--s1)}
.bar-title{font-size:.95rem;font-weight:600;color:var(--ink-2)}
/* THE BAR'S RIGHT END IS WHAT BELONGS TO THE WHOLE VISIT: who is signed in, and signing out. ~~the way back to the
 * site~~ is the logo since 2026-09-26 ("airside logosunda olsun link tıklansın"). */
.bar-end{margin-left:auto;display:flex;align-items:center;gap:var(--s4);min-width:0}
.who{display:flex;align-items:center;gap:var(--s2);min-width:0;font-size:.9rem;color:var(--ink-2)}
.who-dot{
  flex:none;width:28px;height:28px;border-radius:50%;display:grid;place-items:center;
  background:var(--ink);color:var(--on-ink);font-size:.78rem;font-weight:600;
}
.who-mail{max-width:16rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* SIGN OUT IS A FORM (controller, 2026-09-10: "sign out ustte olmali goz onunde olmali"): it changes state, so it cannot
 * be an anchor. A quiet outlined pill, the one control in the bar. */
.bar-end form.signout{display:flex;margin:0}
.bar-end form.signout button{
  font:inherit;font-size:.86rem;font-weight:600;color:var(--ink);white-space:nowrap;
  background:var(--card);border:1px solid var(--line);border-radius:999px;padding:6px 14px;cursor:pointer;
  transition:border-color var(--quick) var(--ease),background-color var(--quick) var(--ease);
}
.bar-end form.signout button:hover{border-color:var(--line-hover);background:var(--sunk)}

.wrap{max-width:44rem;margin:0 auto;padding:var(--s7) var(--s5) var(--s8)}
.wrap.with-rail{
  max-width:76rem;display:grid;grid-template-columns:12.5rem minmax(0,1fr);
  column-gap:var(--s7);padding-top:var(--s6);
}
.with-rail > footer{grid-column:1 / -1}

/* SIGNING IN: THE ACCOUNT'S BAR, AND THE FORM ALONE IN THE MIDDLE (controller, 2026-09-26: "sign in signup ı
 * düzeltmemişsin", then "your airside vs yazıları a free hour vs sil hepini" and "düzgün minimal olsun"). Nothing beside
 * the form: the page asks for one thing. The buttons take the column's width. */
.wrap.auth{max-width:76rem;padding-top:clamp(var(--s7),10vh,120px)}
.wrap.auth > main{max-width:26rem;margin:0 auto}
.wrap.auth > main .actions button{width:100%;justify-content:center}

/* THE RAIL. Quiet links, and the page you are on is a filled row, the way a settings sidebar marks it: six destinations
 * of one kind, and one button on the page that actually does something. Sticky, so the account's pages stay in reach down
 * a long Licence page. */
.rail{position:sticky;top:calc(56px + var(--s3) + var(--s5));align-self:start;display:flex;flex-direction:column;gap:2px}
.rail a{
  display:block;padding:9px var(--s3);border-radius:12px;
  font-size:.95rem;text-decoration:none;color:var(--ink-2);
  transition:background-color var(--quick) var(--ease),color var(--quick) var(--ease);
}
.rail a:hover{background:var(--sunk);color:var(--ink)}
.rail a.now{color:var(--ink);font-weight:600;padding:8px calc(var(--s3) - 1px)}
/* THE DISCORD ROW (2026-09-27): set apart from the account's own pages by a hairline, the emblem in Discord's colour, and
 * one quiet line saying why to go. It leaves the site, in a new tab. */
.rail a.rail-out{display:flex;align-items:center;gap:10px;margin-top:var(--s3);padding-top:calc(9px + var(--s3));
  border-top:1px solid var(--line);border-radius:0 0 12px 12px}
.rail a.rail-out img{flex:none;display:block}
.rail a.rail-out span{display:flex;flex-direction:column;line-height:1.2}
.rail a.rail-out small{font-size:.78rem;color:var(--ink-3)}

/* THE GLASS: ONE RECIPE FOR THE BAR AND FOR THE PAGE YOU ARE ON IN THE RAIL (controller, 2026-09-26: "soldaki menüleri
 * licence vs seçince de navbardaki buz şeysi olsun"), so the two can never drift apart. The card colour, solid, where the
 * browser cannot blur; 42 per cent of it with a 20px blur where it can. */
.bar-in,.rail a.now{background:var(--card);border:1px solid var(--line);box-shadow:0 8px 28px rgba(24,24,27,.08)}
@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .bar-in,.rail a.now{
    background:color-mix(in srgb,var(--card) 42%,transparent);
    border-color:color-mix(in srgb,var(--line) 70%,transparent);
    -webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);
  }
}

main{display:block;min-width:0}

/* TWO SHORT CARDS OF DIFFERENT KINDS SIT SIDE BY SIDE on a wide screen, and one takes the whole row when it is alone. */
.pair{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,21rem),1fr));
  column-gap:var(--s5);align-items:start;
}

footer{margin-top:var(--s8);padding-top:var(--s5);border-top:1px solid var(--line)}
footer nav{display:flex;gap:var(--s5);flex-wrap:wrap;margin-bottom:var(--s4)}
footer nav a{font-size:.9rem;text-decoration:none;color:var(--ink-3)}
footer nav a:hover{color:var(--ink)}
footer p{margin:0;color:var(--ink-3);font-size:.82rem;max-width:52ch;line-height:1.55}

/* ON A PHONE THE RAIL FOLDS INTO ONE SCROLLING ROW ABOVE THE PAGE, and the page is one column again. */
@media (max-width:56rem){
  .bar{padding:var(--s2) var(--s4) 0}
  .bar-in{padding:0 8px 0 var(--s3);border-radius:14px}
  .bar-sep,.bar-title,.who-mail{display:none}
  .wrap.with-rail{display:block;padding-top:var(--s4)}
  .rail{
    position:static;flex-direction:row;overflow-x:auto;gap:var(--s1);
    margin:0 calc(-1 * var(--s4)) var(--s5);padding:0 var(--s4) var(--s3);
    border-bottom:1px solid var(--line);scrollbar-width:none;
  }
  .rail::-webkit-scrollbar{display:none}
  .rail a{white-space:nowrap}
  .rail a.rail-out{margin-top:0;padding-top:9px;border-top:0;border-radius:12px}
  .rail a.rail-out small{display:none}
  /* Signing in on a phone: the form first, the rest of the story under it. */
  .wrap.auth{padding-top:var(--s5)}
}

/* ------------------------------------------------------------------------------------------------
 * TYPE. One large light heading, then small grey section labels. The labels are SENTENCE CASE and not
 * uppercase with letterspacing: that treatment belongs to the deck and the marketing site, where it
 * reads as instrumentation. Here it would read as shouting at somebody doing paperwork.
 */
h1,h2,h3,p,ul,ol,dl,dd,figure{margin:0}
ul{padding:0;list-style:none}

h1{
  font-weight:300;font-size:clamp(2rem,4vw,2.6rem);line-height:1.12;
  letter-spacing:-.022em;margin-bottom:var(--s2);text-wrap:balance;
}
h1 b{font-weight:600}

h2{
  font-size:.92rem;font-weight:600;letter-spacing:-.004em;color:var(--ink-3);
  margin:var(--s6) 0 var(--s3);
}

h3{font-size:1.02rem;font-weight:600;letter-spacing:-.008em;color:var(--ink)}

p{margin-top:var(--s3);color:var(--ink-2);max-width:62ch}
p:first-child{margin-top:0}

a{color:var(--ink);text-decoration:underline;text-decoration-color:var(--line);text-underline-offset:3px}
a:hover{text-decoration-color:var(--ink-3)}

.muted{color:var(--ink-3);font-size:.9rem}
.lede{color:var(--ink-2);font-size:1.08rem;max-width:54ch;margin-top:var(--s2)}

/* ------------------------------------------------------------------------------------------------
 * CARDS AND ROWS
 *
 * A white card on a grey page, a hairline border, and almost no shadow. Rows inside are divided by a
 * lighter rule than the card's own edge, so the group reads as one object with parts rather than as
 * a stack of separate things.
 */
.card{
  background:var(--card);
  border:1px solid var(--line);
  border-radius:var(--r);
  padding:var(--s5);
  margin-top:var(--s4);
  box-shadow:var(--shadow);
}
.card > h2:first-child{margin-top:0}
.card > h3:first-child{margin-top:0}

.row{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s4);
  padding:var(--s4) 0;
  border-top:1px solid var(--line-2);
  flex-wrap:wrap;
}
.row:first-of-type{border-top:0;padding-top:0}
.row-main{min-width:0;font-size:.98rem}
.row-val{color:var(--ink-3);font-size:.88rem}
.row-act{margin-left:auto}

/* THE LICENCE KEY IS THE ONE THING ON THIS PAGE SOMEBODY COPIES, so it is set as a field rather than
 * as text: a sunken chip, selectable, wide enough not to wrap on a phone. */
.key{
  display:inline-block;
  font-family:var(--mono);font-weight:500;font-size:1rem;letter-spacing:.02em;
  color:var(--ink);background:var(--sunk);
  border:1px solid var(--line);border-radius:var(--r-s);
  padding:var(--s2) var(--s3);
  user-select:all;word-break:break-all;
}
code,.mono{font-family:var(--mono);font-weight:500;font-size:.8rem;color:var(--ink-3)}

/* AN AMOUNT IS NOT A KEY, AND A VERSION IS NOT A KEY EITHER. Both were set in .key when the account
 * pages were written, which put a sunken, select-all, copy-me chip around two figures nobody copies.
 * The chip is a control; these are values, and they are read. The amount is the largest thing on an
 * order because it is the thing being looked up. */
.amount{font-size:1.35rem;font-weight:600;letter-spacing:-.014em;color:var(--ink)}
.amount .cur{font-size:.9rem;font-weight:600;color:var(--ink-3);margin-right:.4em;letter-spacing:.02em}
.ver{font-family:var(--mono);font-weight:500;font-size:1rem;color:var(--ink);letter-spacing:-.01em}

/* A definition list for facts that are read rather than acted on. */
.facts{
  border:1px solid var(--line);border-radius:var(--r);background:var(--card);
  margin-top:var(--s4);overflow:hidden;
}
.fact{
  display:flex;justify-content:space-between;gap:var(--s4);
  padding:var(--s4) var(--s5);
  border-top:1px solid var(--line-2);flex-wrap:wrap;
}
.fact:first-child{border-top:0}
.fact dt{color:var(--ink-3);font-size:.92rem}
.fact dd{color:var(--ink);font-size:.95rem;text-align:right}

/* A BOX INSIDE A BOX IS A MISTAKE THIS FILE SHOULD MAKE IMPOSSIBLE. A .facts list carries its own
 * border, radius and white fill so it can stand alone on the grey page; dropped inside a .card it
 * became a white panel on a white panel, hairline against hairline, which reads as a nested object
 * where there is only one. Contextual rather than a modifier class, so it cannot be forgotten at the
 * next call site. The rows keep their dividers and fall back to the card's own gutter. */
.card > .facts{border:0;background:none;border-radius:0;margin-top:var(--s2)}
.card > .facts > .fact{padding-left:0;padding-right:0}
.card > .facts > .fact:first-child{border-top:1px solid var(--line-2)}

/* ------------------------------------------------------------------------------------------------
 * STATUS. Colour is never the only signal: every tag carries its word, which is the deck's own rule.
 */
.tag{
  display:inline-block;
  font-size:.78rem;font-weight:600;letter-spacing:.01em;
  padding:3px 9px;border-radius:999px;white-space:nowrap;
}
.tag.ok{color:var(--ok);background:var(--ok-bg)}
.tag.warn{color:var(--warn);background:var(--warn-bg)}
.tag.bad{color:var(--bad);background:var(--bad-bg)}

/* ------------------------------------------------------------------------------------------------
 * SUPPORTER. The plate is an airfield location sign: yellow letters and a yellow border on black, the
 * sign that tells a pilot where they ARE, which is what this one does for the account. 11.65:1. It is
 * the page's only black and yellow, and only a supporter's page has it.
 *
 * THE PAGE COLOURS ARE THREE BUTTONS, one press each. The dot is the light the ground is named for, at
 * full strength, so the button says which colour it is before its word does; the word is what carries
 * it, and aria-pressed says which one is on.
 */
.supporter{display:flex;flex-direction:column;align-items:flex-start;gap:var(--s3)}
.supporter p{margin-top:0}
.plate{
  margin-left:3px;
  padding:6px 14px 5px;
  font:600 1rem/1.1 var(--sign);letter-spacing:.14em;text-transform:uppercase;
  color:#F6C90E;background:#16140D;
  border:2px solid #F6C90E;border-radius:3px;
  box-shadow:0 0 0 3px #16140D;
}
.grounds{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap}
.grounds-label{font-size:.88rem;color:var(--ink-3);margin-right:var(--s1)}
button.swatch{
  display:inline-flex;align-items:center;gap:var(--s2);
  padding:6px var(--s3);font-size:.88rem;font-weight:500;
  color:var(--ink-2);background:var(--card);border:1px solid var(--line);border-radius:999px;
}
button.swatch::before{
  content:"";flex:none;width:10px;height:10px;border-radius:50%;
  box-shadow:inset 0 0 0 1px rgba(24,24,27,.28);
}
button.swatch-taxiway::before{background:#2B6CD4}
button.swatch-centreline::before{background:#1E9E57}
button.swatch-sign::before{background:#F2C230}
button.swatch-default::before{background:#FAF6EC}
button.swatch-windsock::before{background:#FF7A1A}
button.swatch-runway::before{background:#7A818C}
button.swatch-midnight::before{background:#4B2E83}
button.swatch-wine::before{background:#7B1E34}
button.swatch:hover{color:var(--ink);background:var(--card);box-shadow:var(--shadow)}
button.swatch:active{background:var(--card);box-shadow:none}
button.swatch[aria-pressed="true"]{color:var(--ink);border-color:var(--ink);box-shadow:inset 0 0 0 1px var(--ink)}

/* A notice is the product telling the customer something, not a control. */
.notice{
  background:var(--warn-bg);border:1px solid rgba(138,90,0,.16);
  border-radius:var(--r-s);padding:var(--s3) var(--s4);margin-top:var(--s3);
}
.notice.bad{background:var(--bad-bg);border-color:rgba(180,35,28,.18)}
/* A THING THAT WENT RIGHT, and it needs saying: the one moment a customer most wants to be told
 * plainly that it worked is the moment they have just moved the address they sign in with. */
.notice.ok{background:var(--ok-bg);border-color:rgba(19,122,69,.18)}
.notice p{margin-top:0;color:var(--ink-2);font-size:.92rem;max-width:none}

/* THE ACCOUNT PAGE NO LONGER CARRIES THE LIVE NOTICES, so `.knowing` is gone with them (controller,
 * 2026-09-06). It was written the same day: the eight lines the installer shows, set as one quiet
 * card under the licence after a first attempt put them ABOVE it as eight amber warning boxes. The
 * reasoning for having them at all was that somebody opening the portal is often somebody with a
 * problem - that stands, and the answer is the site's own known limits page, which is where the list
 * is published in full and where it is read before anybody pays. THE PORTAL'S FOOTER LINK TO IT WENT
 * TOO, an hour after this paragraph first cited it as the replacement; a comment that names a route
 * somebody has since removed is the defect this session kept finding, so it is corrected rather than
 * left to be read as true. (AND THE PAGE ITSELF CAME OFF THE SITE ON 2026-10-10, at the controller's
 * instruction: the list is not published anywhere now, and this note is the record of where it was.)
 * Named here rather than deleted silently, for the same reason button.danger is: a rule nothing uses
 * is a rule the next reader takes for load bearing. */

/* WHAT CHANGED IN A BUILD IS A LIST OF CHANGES. It was one paragraph with line breaks in it, so three
 * separate things read as one long sentence and the eye had nothing to count. */
.notes{margin-top:var(--s3);display:flex;flex-direction:column;gap:var(--s2)}
.notes li{position:relative;padding-left:var(--s4);color:var(--ink-2);font-size:.95rem;line-height:1.55;max-width:62ch}
.notes li::before{content:"";position:absolute;left:2px;top:.62em;width:4px;height:4px;border-radius:50%;background:var(--ink-3)}

/* ------------------------------------------------------------------------------------------------
 * FORMS AND BUTTONS
 */
label{display:block;margin-bottom:var(--s2);font-size:.92rem;font-weight:600;color:var(--ink)}

/* A CONTROL AND ITS LABEL, SPACED AS ONE THING. `label` cannot carry the top margin itself: on the
 * sign in page it is the first child of its card and would push the field off its own edge. So the
 * space belongs to the group, and the group knows when it is first. */
.field{margin-top:var(--s5)}
.field:first-child{margin-top:0}

input[type=email],input[type=text]{
  width:100%;padding:11px var(--s3);
  border:1px solid var(--line);border-radius:var(--r-s);
  background:var(--card);color:var(--ink);
  font:400 1rem/1.4 var(--ui);
  transition:border-color var(--quick) var(--ease), box-shadow var(--quick) var(--ease);
}
input[type=email]:hover,input[type=text]:hover{border-color:var(--line-hover)}
input[type=email]:focus,input[type=text]:focus{
  outline:none;border-color:var(--ink);box-shadow:0 0 0 3px rgba(24,24,27,.08);
}
/* ------------------------------------------------------------------------------------------------
 * SIX BOXES, ONE DIGIT EACH. This replaced a single wide field with letterspacing faked into it, and
 * the difference is not decoration: a person reading six characters off a screen and typing them into
 * one box has to hold their place themselves, and a box per digit holds it for them. It is also the
 * shape every phone, bank and password manager now expects, which is why `autocomplete="one-time-code"`
 * on the first box fills the whole group on iOS.
 *
 * `ch` UNITS AND NOT PIXELS, so a box is sized by the typeface it holds rather than by a number that
 * happens to look right at one weight. `aspect-ratio` keeps it square as the width follows.
 */
.otp{display:flex;gap:var(--s2);margin-top:var(--s2)}
.otp input{
  width:2.4ch;flex:1 1 0;min-width:0;max-width:3.4rem;aspect-ratio:1/1.15;
  padding:0;text-align:center;
  font-family:var(--mono);font-weight:500;font-size:1.5rem;letter-spacing:0;
  border:1px solid var(--line);border-radius:var(--r-s);
  background:var(--card);color:var(--ink);
  transition:border-color var(--quick) var(--ease), box-shadow var(--quick) var(--ease);
}
.otp input:hover{border-color:var(--line-hover)}
.otp input:focus{outline:none;border-color:var(--ink);box-shadow:0 0 0 3px rgba(24,24,27,.08)}
/* NO "FILLED" STATE, AND THAT IS A CHOICE. Six identical squares give no sense of progress, so a
 * darker border on a filled box is tempting; there is no honest selector for it. `:placeholder-shown`
 * needs a placeholder these do not have, `:valid` is true of an empty box because the pattern only
 * rejects what is there, and the remaining route is a class toggled from JavaScript - which would put
 * the appearance of the field behind a script the no-script path is written to survive without. The
 * caret and the focus ring are the feedback, and they are real in both worlds. */

/* THE PRIMARY BUTTON IS NEAR BLACK, NOT ORANGE, and that is the decision that makes this page look
 * like the thing that was asked for. On a white ground an orange button is the loudest object on the
 * screen, which is right on a page that is selling and wrong on a page where somebody is releasing a
 * machine. The brand keeps the mark; the action keeps the ink. */
button,.button{
  display:inline-block;
  padding:11px var(--s5);
  font:600 .96rem/1.2 var(--ui);letter-spacing:-.004em;
  text-decoration:none;text-align:center;
  color:var(--on-ink);background:var(--ink);
  border:1px solid var(--ink);border-radius:var(--r-s);
  cursor:pointer;
  transition:background var(--quick) var(--ease), box-shadow var(--quick) var(--ease);
}
button:hover,.button:hover{background:var(--ink-hover);box-shadow:var(--shadow-lift)}
button:active,.button:active{background:var(--ink);box-shadow:none}

button.ghost,.button.ghost{
  background:var(--card);color:var(--ink-2);border-color:var(--line);
  padding:7px var(--s3);font-size:.88rem;
}
button.ghost:hover,.button.ghost:hover{background:var(--card);color:var(--ink);border-color:var(--line-hover);box-shadow:var(--shadow)}

/* THERE IS NO DESTRUCTIVE BUTTON ON THIS HOST ANY MORE, so the styles that dressed one are gone with
 * it: `button.danger`, `.card.grave` and `h2.grave` were written for the self service account closure
 * on 2026-09-06 and deleted the same day, when the controller decided that closing an account is a
 * request staff act on rather than something a browser can do. They are named here rather than left
 * in place because a rule nothing uses is a rule the next reader takes for load bearing, and because
 * somebody re-adding a red button should have to decide what it looks like rather than inherit it.
 * The red TOKENS stay: .tag.bad and .notice.bad still say what state a thing is in. */

button[disabled],.button[disabled]{opacity:.4;cursor:not-allowed;box-shadow:none}

button:focus-visible,.button:focus-visible,a:focus-visible{
  outline:2px solid var(--ink);outline-offset:2px;
}

form.inline{display:inline}
.actions{display:flex;gap:var(--s3);align-items:center;flex-wrap:wrap;margin-top:var(--s5)}

/* ------------------------------------------------------------------------------------------------
 * EMPTY STATES. They say what happens next rather than reporting an absence.
 */
.empty{
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:var(--s7) var(--s5);margin-top:var(--s4);text-align:center;
}
.empty p{color:var(--ink-3);margin-left:auto;margin-right:auto}
.empty .actions{justify-content:center}

/* ------------------------------------------------------------------------------------------------
 * NARROW. A row of label, value and control is the one shape that breaks first, so below this the
 * control drops under its own row rather than squeezing the label to nothing.
 */
@media (max-width:36rem){
  .wrap{padding:var(--s6) var(--s4) var(--s7)}
  .bar-end{gap:var(--s3)}
  .who{display:none}
  .row{align-items:flex-start}
  .row-act{margin-left:0;width:100%;margin-top:var(--s2)}
  .fact{flex-direction:column;gap:2px}
  .fact dd{text-align:left}
  /* The boxes already flex; this only stops them growing past what a thumb needs on a phone. */
  .otp{gap:6px}
  .otp input{font-size:1.25rem;max-width:none}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition:none!important;animation:none!important}
}

/* ------------------------------------------------------------------------------------------------ spacing utilities ----------
 * One class per style= attribute that would otherwise sit in a template, and they exist for exactly
 * that reason: a style attribute cannot be rescued by a CSP hash without 'unsafe-hashes', which would
 * weaken the whole origin.
 *
 * `.note-hint` IS NAMED IN ops/bite_manifest.txt: the entry an-element-that-carries-a-style-attribute
 * mutates the exact line `<p class="muted note-hint">The code works once and expires in a few
 * minutes.</p>` in signin.html. Renaming this class, or that line, breaks the proof that the gate
 * works. It is kept for that reason as much as for this one.
 */
.note-hint  {margin:var(--s3) 0 0}
.note-retry {margin:var(--s3) 0 0;color:var(--bad)}
.note-sub   {margin:var(--s2) 0 0}
.gap-sm     {margin-top:var(--s3)}
.gap-md     {margin-top:var(--s4)}
.gap-lg     {margin-top:var(--s5)}
/* THE BREAK AN h2 WOULD HAVE MADE. Every other page opens h1, lede, then a section label whose 36px
 * top margin separates the introduction from the content. The sign in page has no section label -
 * "Purchase e-mail" is the field's own label and a heading above it would say the same thing twice -
 * so its card followed the lede by 16px and the heading, the sentence and the form read as one dense
 * block with no hierarchy at all. This is that missing 36px, and nothing else. */
.gap-xl     {margin-top:var(--s6)}

/* ---------------------------------------------------------------- your shots (share.html) ---------------
 * The one page in the portal that takes files. Every control on it is the portal's own shape: the same
 * field, label and button, with three additions a file form needs and the rest of the portal did not -
 * a URL field, a file picker and a checkbox that is a sentence. */
input[type=url]{
  width:100%;padding:11px var(--s3);
  border:1px solid var(--line);border-radius:var(--r-s);
  background:var(--card);color:var(--ink);
  font:400 1rem/1.4 var(--ui);
  transition:border-color var(--quick) var(--ease), box-shadow var(--quick) var(--ease);
}
input[type=url]:hover{border-color:var(--line-hover)}
input[type=url]:focus{outline:none;border-color:var(--ink);box-shadow:0 0 0 3px rgba(24,24,27,.08)}
input::placeholder{color:var(--placeholder)}

.steps{margin:var(--s5) 0 0;padding:0;list-style:none;counter-reset:step;display:grid;gap:var(--s3)}
.steps li{counter-increment:step;position:relative;padding-left:40px;color:var(--ink-2);max-width:60ch}
.steps li::before{
  content:counter(step);position:absolute;left:0;top:-1px;width:26px;height:26px;border-radius:50%;
  display:grid;place-items:center;font:600 .82rem/1 var(--ui);color:var(--ink);background:var(--sunk);
  border:1px solid var(--line);
}
.steps b{font-weight:600;color:var(--ink)}

.opt{margin-left:6px;font-weight:400;font-size:.82rem;color:var(--ink-3)}
.hint{margin-top:var(--s2);font-size:.86rem;color:var(--ink-3);max-width:none}
.pair{display:grid;grid-template-columns:1fr 1fr;gap:var(--s4);margin-top:var(--s5)}
.pair .field{margin-top:0}

.drop{border:1.5px dashed var(--line);border-radius:var(--r);background:var(--sunk);padding:var(--s4)}
.drop:focus-within{border-color:var(--ink)}
.drop input[type=file]{width:100%;font:400 .95rem/1.4 var(--ui);color:var(--ink-2)}
.drop input[type=file]::file-selector-button{
  margin-right:var(--s3);padding:9px var(--s4);
  font:600 .92rem/1.2 var(--ui);color:var(--ink);background:var(--card);
  border:1px solid var(--line);border-radius:var(--r-s);cursor:pointer;
  transition:border-color var(--quick) var(--ease), box-shadow var(--quick) var(--ease);
}
.drop input[type=file]::file-selector-button:hover{border-color:var(--ink-3);box-shadow:var(--shadow)}

.consent{
  display:flex;gap:var(--s3);align-items:flex-start;margin-top:var(--s5);
  font-weight:400;font-size:.92rem;color:var(--ink-2);line-height:1.5;cursor:pointer;
}
.consent input{flex:none;width:18px;height:18px;margin:2px 0 0;accent-color:var(--ink);cursor:pointer}
/* The settings card opens with the box, so its top margin would be empty space above the first line. */
.updates-form .consent{margin-top:0}
.shots-form .actions{margin-top:var(--s5)}
/* The form's first child is the hidden CSRF input, so .field:first-child never matches here and the card opened
 * with a field's worth of empty space. first-of-type counts only the divs. */
.shots-form > .field:first-of-type{margin-top:0}

.shots{margin-top:var(--s4);display:grid;grid-template-columns:1fr 1fr;gap:var(--s4)}
.shot{
  display:flex;flex-direction:column;background:var(--card);border:1px solid var(--line);
  border-radius:var(--r);overflow:hidden;box-shadow:var(--shadow);
}
.shot-pic{display:block;width:100%;height:auto;aspect-ratio:16/9;object-fit:cover;background:var(--sunk)}
.shot-pic.video,.shot-pic.gone{
  display:grid;place-items:center;font:600 .9rem/1 var(--ui);color:var(--ink-3);text-decoration:none;
}
.shot-pic.video{background:#18181B;color:#F2EFE3}
.shot-body{padding:var(--s4);display:flex;flex-direction:column;gap:var(--s1)}
.shot-body p{margin-top:0}
.shot-top{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);margin-bottom:var(--s1)}
.shot-caption{color:var(--ink);font-size:.95rem;overflow-wrap:anywhere}
.tag.quiet{color:var(--ink-3);background:var(--sunk)}

.withdraw{margin-top:var(--s2)}
.withdraw summary{
  display:inline-block;cursor:pointer;list-style:none;font-size:.88rem;color:var(--ink-3);
  text-decoration:underline;text-decoration-color:var(--line);text-underline-offset:3px;
}
.withdraw summary::-webkit-details-marker{display:none}
.withdraw summary:hover{color:var(--ink)}
.withdraw[open] summary{color:var(--ink)}
.withdraw form{margin-top:var(--s2);display:flex;flex-direction:column;gap:var(--s2);align-items:flex-start}

@media (max-width: 40rem){
  .pair,.shots{grid-template-columns:1fr}
}

/* ---------------------------------------------------------------- the shots picker (shots.js) ------------
 * Only drawn when the script runs: it adds .enhanced to the box, hides the plain field WITHOUT removing it (it is
 * still what the form posts, and still what a keyboard reaches), and lays the chosen pictures out as tiles with a
 * tile to add more. Without the script none of this applies and the plain field shows as before. */
.label-row{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s3)}
.label-row .count{font-size:.85rem;font-variant-numeric:tabular-nums}
.drop{position:relative}
.drop.enhanced input[type=file]{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;
}
.drop.over{border-color:var(--ink);background:var(--drop)}
.picks{display:grid;grid-template-columns:repeat(auto-fill,minmax(9.5rem,1fr));gap:var(--s3);margin:0 0 var(--s3)}
.pick{
  position:relative;display:flex;flex-direction:column;min-width:0;
  background:var(--card);border:1px solid var(--line);border-radius:var(--r-s);overflow:hidden;
}
.pick img{display:block;width:100%;height:auto;aspect-ratio:16/9;object-fit:cover;background:var(--sunk)}
.pick-meta{display:flex;flex-direction:column;gap:2px;padding:var(--s2) var(--s3);min-width:0}
.pick-name{font-size:.84rem;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pick-dims{font-size:.76rem;color:var(--ink-3);font-variant-numeric:tabular-nums}
button.pick-remove{
  position:absolute;top:6px;right:6px;width:28px;height:28px;padding:0;
  border:0;border-radius:50%;background:rgba(24,24,27,.72);color:#fff;
  font:500 1.05rem/28px var(--ui);text-align:center;box-shadow:none;
}
button.pick-remove:hover{background:rgba(24,24,27,.92);box-shadow:none}
.pick-add label{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
  height:100%;min-height:8.5rem;margin:0;padding:var(--s3);
  border:1.5px dashed var(--line);border-radius:var(--r-s);background:var(--card);
  font-size:.9rem;font-weight:600;color:var(--ink);text-align:center;cursor:pointer;
  transition:border-color var(--quick) var(--ease);
}
.pick-add label:hover{border-color:var(--ink-3)}
.pick-add .plus{font:300 1.7rem/1 var(--ui);color:var(--ink-3)}
.pick-add .sub{font-size:.8rem;font-weight:400;color:var(--ink-3)}
.drop.enhanced input[type=file]:focus-visible ~ .picks .pick-add label{outline:2px solid var(--ink);outline-offset:2px}
.pick-errors{margin-top:var(--s2);display:flex;flex-direction:column;gap:4px}
.pick-errors li{position:relative;padding-left:var(--s4);font-size:.86rem;color:var(--bad);max-width:62ch}
.pick-errors li::before{content:"";position:absolute;left:2px;top:.62em;width:5px;height:5px;border-radius:50%;background:var(--bad)}
.refused{margin-top:var(--s2);display:flex;flex-direction:column;gap:4px}
.refused li{position:relative;padding-left:var(--s4);font-size:.9rem;color:var(--ink-2)}
.refused li::before{content:"";position:absolute;left:2px;top:.62em;width:4px;height:4px;border-radius:50%;background:var(--ink-3)}
button[data-shots-send][disabled]{opacity:.6}
