:root{
  --bg:#08140f;--panel:#10251b;--line:#284638;--text:#f2f6ef;--muted:#9caf9f;
  --green:#9ae691;--paper:#f6f4ee;--ink:#152019;--clay:#9b6848;
  /* ---- theme surface tokens (2026-07-31, dark-mode toggle) -- everything
     below used to be hardcoded hex scattered through this file. Consolidated
     into named roles so html.theme-light (bottom of file) can redefine the
     whole palette in one place instead of chasing every rule. Values here
     are the defaults, i.e. the dark theme this app always looked like. ---- */
  --card:#0d2117;--well:#07130d;--hover:#133123;--accent-soft:#173524;
  --accent-line:#4d8059;--on-accent:#0a1710;--lead:#becbc1;--warn:#e7c77b;
  --danger-bg:#2b1712;--danger-line:#734a3d;--danger-text:#f1a187;
  --danger-bg-hover:#3b1d16;--danger-line-hover:#e89a7b;
  --status-over-line:#a96050;--status-over-text:#f2a58e;--status-under-line:#477956;
  --track:#1d4030;
  font-family:Inter,ui-sans-serif,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  color:var(--text);background:var(--bg);font-synthesis:none
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;min-width:320px;background:radial-gradient(circle at 20% 0,var(--accent-soft) 0,var(--bg) 32%);color:var(--text)}
button,input,select{font:inherit}
button,a{transition:.15s ease}
button{cursor:pointer}
[hidden]{display:none!important}
.site-header,.app-header{width:min(1180px,calc(100% - 40px));height:76px;margin:auto;display:flex;align-items:center;justify-content:space-between}
.header-actions{display:flex;align-items:center;gap:10px;color:var(--muted);font-size:13px}
.passkey-status{max-width:230px;color:var(--green);font-size:11px}
.brand{color:var(--text);font-size:16px;font-weight:800;letter-spacing:.05em;text-decoration:none}
.quiet-button,.secondary-button{border:1px solid var(--line);border-radius:9px;background:transparent;color:inherit;padding:9px 14px}
.quiet-button:hover,.secondary-button:hover{border-color:var(--green);color:var(--green)}
.danger-button{border-color:var(--danger-line);color:var(--danger-text)}
.danger-button:hover{border-color:var(--danger-line-hover);background:var(--danger-bg);color:var(--danger-text)}

/* ---- header dropdowns: settings (gear) + account (avatar), both
   headers -- generic [data-dropdown]/[data-dropdown-panel] wiring lives
   in app.js's initDropdowns(), one implementation for both. ---- */
.dropdown{position:relative}
.icon-button{display:grid;place-items:center;width:38px;height:38px;border:1px solid var(--line);border-radius:10px;background:transparent;color:var(--muted);font-size:16px;padding:0}
.icon-button:hover,.icon-button[aria-expanded="true"]{border-color:var(--green);color:var(--green)}
.avatar-button{display:grid;place-items:center;width:38px;height:38px;border:1px solid var(--line);border-radius:99px;background:var(--accent-soft);color:var(--green);font-weight:800;font-size:14px;padding:0;text-transform:uppercase}
.avatar-button:hover,.avatar-button[aria-expanded="true"]{border-color:var(--green)}
.dropdown-panel{position:absolute;top:calc(100% + 8px);right:0;z-index:25;width:250px;border:1px solid var(--line);border-radius:14px;background:var(--panel);padding:16px;box-shadow:0 20px 60px rgba(0,0,0,.35)}
.dropdown-label{margin:0 0 2px;color:var(--muted);font-size:10px;text-transform:uppercase;letter-spacing:.06em}
.dropdown-heading{margin:0 0 10px;color:var(--text);font-size:13px;font-weight:700;overflow-wrap:anywhere}
.dropdown-panel .passkey-status{display:block;margin:0 0 12px}
.dropdown-panel .quiet-button{display:block;width:100%;margin-top:8px;text-align:center}
.dropdown-field{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:0 0 10px;color:var(--muted);font-size:12px}
.dropdown-field select{border:1px solid var(--line);border-radius:7px;background:var(--well);color:var(--text);padding:6px 8px;font-size:12px}
.dropdown-hint{margin:10px 0 0;color:var(--muted);font-size:11px;line-height:1.4}
/* ---- dark-mode pill switch (settings dropdown) -- checkbox input is kept
   for real keyboard/screen-reader semantics, just visually hidden and
   replaced by the two spans next to it via the adjacent-sibling selectors
   below. No JS needed for the visual state, app.js only reads/writes
   .checked and persists it into prefs.theme. ---- */
.switch-field{cursor:pointer}
.switch{position:relative;display:inline-block;flex:0 0 auto;width:38px;height:22px}
.switch input{position:absolute;inset:0;z-index:1;margin:0;opacity:0;cursor:pointer}
.switch-track{position:absolute;inset:0;border-radius:99px;background:var(--line);transition:background .15s ease}
.switch-thumb{position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:99px;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.35);transition:transform .15s ease}
.switch input:checked+.switch-track{background:var(--green)}
.switch input:checked+.switch-track .switch-thumb{transform:translateX(16px)}
.switch input:focus-visible+.switch-track{outline:2px solid var(--green);outline-offset:2px}
.hero{width:min(1180px,calc(100% - 40px));min-height:620px;margin:auto;display:grid;grid-template-columns:1.25fr .75fr;align-items:center;gap:80px;padding:60px 0 100px}
.eyebrow{margin:0 0 14px;color:var(--green);font-size:11px;font-weight:800;letter-spacing:.16em;text-transform:uppercase}
.hero h1{margin:0;font-family:Georgia,"Times New Roman",serif;font-size:clamp(48px,7vw,88px);font-weight:500;line-height:.96;letter-spacing:-.055em}
.lead{max-width:620px;margin:28px 0 34px;color:var(--lead);font-size:20px;line-height:1.55}
.primary-link,.primary-button{display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--green);border-radius:9px;background:var(--green);color:var(--on-accent);padding:11px 17px;font-weight:800;text-decoration:none}
.primary-link:hover,.primary-button:hover{filter:brightness(1.08);transform:translateY(-1px)}
/* Was a hardcoded rgba(16,37,27,.82) -- the old dark --panel value at 82%
   opacity, missed during the light-theme token conversion (2026-07-31).
   In light theme that left a dark-green glass card with dark (var(--ink))
   text on top of it -- barely readable. color-mix keeps the translucent
   "glass over the hero gradient" look while actually following the
   theme's --card token. */
.hero-card{border:1px solid var(--line);border-radius:22px;background:color-mix(in srgb, var(--card) 82%, transparent);padding:30px;box-shadow:0 28px 80px rgba(0,0,0,.3)}
.hero-card>span{color:var(--muted);font-size:13px}
.hero-card>strong{display:block;margin:10px 0 24px;font-family:Georgia,serif;font-size:52px;font-weight:500}
.weight-line{height:10px;border-radius:99px;background:var(--track);overflow:hidden}.weight-line i{display:block;width:8%;height:100%;background:var(--green)}
.hero-card dl{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin:24px 0 0}
.hero-card dl div{border:1px solid var(--line);border-radius:10px;padding:12px}
.hero-card dt{color:var(--muted);font-size:11px}.hero-card dd{margin:5px 0 0;font-weight:700}
.planner-section{width:min(1500px,calc(100% - 40px));margin:0 auto 64px}
.section-heading{display:flex;align-items:end;justify-content:space-between;gap:30px;margin-bottom:20px}
.section-heading h2{margin:0;font-family:Georgia,serif;font-size:38px;font-weight:500}
.section-heading>p{max-width:520px;margin:0;color:var(--muted);line-height:1.5}
.planner{position:relative;display:grid;grid-template-columns:340px minmax(0,1fr);min-height:620px;border:1px solid var(--line);border-radius:20px;overflow:visible;background:var(--card);box-shadow:0 20px 70px rgba(0,0,0,.22)}
.planner-sidebar{padding:28px 22px;border-right:1px solid var(--line);border-radius:20px 0 0 20px;background:var(--card)}
.list-title{width:100%;border:0;border-bottom:1px solid transparent;background:transparent;color:var(--text);padding:3px 0;font-size:22px;font-weight:800}
.list-title:hover,.list-title:focus{outline:0;border-color:var(--green)}
.list-switcher{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px;margin-top:12px}
.list-switcher select,.list-switcher button{min-width:0;border:1px solid var(--line);border-radius:7px;background:var(--well);color:var(--text);padding:7px;font-size:11px}
.list-switcher button{color:var(--green);white-space:nowrap}
.list-login-hint{margin:10px 0 0;color:var(--muted);font-size:11px;line-height:1.4}
.planner-nav{display:grid;gap:6px;margin:26px 0}
.planner-nav button{display:flex;align-items:center;justify-content:space-between;width:100%;border:1px solid transparent;border-radius:9px;background:transparent;color:var(--text);padding:10px 12px;text-align:left}
.planner-nav button:hover,.planner-nav button.active{border-color:var(--line);background:var(--hover)}
.planner-nav span{min-width:23px;border-radius:99px;background:var(--line);padding:2px 7px;color:var(--green);font-size:11px;text-align:center}
.save-state{color:var(--muted);font-size:12px}
/* Duplicate of the sidebar save-state, placed above .top-stats so it's
   visible without scrolling to the sidebar (easy to miss there, especially
   on mobile where the sidebar sits below the table). Both elements share
   [data-save-state] and get updated together -- see the saveState setter
   in app.js's createPlanner(). Empty text collapses the line to nothing
   via :empty so it doesn't reserve blank space before the first save. */
.save-state-top{display:block;min-height:1em;margin:0 0 10px;text-align:right;font-weight:600}
.save-state-top:empty{display:none}
.planner-content{min-width:0;padding:28px 24px 24px}
/* Used to be pulled up 18px to overlap the planner's top edge -- read as
   the stats "hanging" right at the seam with nothing above them for
   breathing room. Plain in-flow now, with .planner-content's own top
   padding (above) doing the spacing job instead of a negative transform. */
.top-stats{position:relative;z-index:2;display:grid;grid-template-columns:repeat(6,minmax(105px,1fr));gap:12px;margin:0 0 20px}
.top-stats article,.top-stats .top-stat-button{min-width:0;border:1px solid var(--line);border-radius:13px;background:var(--card);padding:11px 15px;box-shadow:0 12px 28px rgba(0,0,0,.18)}
.top-stats span,.top-stats label{display:block;color:var(--muted);font-size:10px;text-transform:uppercase;letter-spacing:.06em}
.top-stats strong{display:block;margin-top:4px;font-size:20px;white-space:nowrap}
/* Inköp is a real <button> now (goes to the shopping view on click) --
   reset the button-specific defaults browsers add so it matches the
   plain <article> boxes next to it pixel for pixel, then layer on a
   hover/focus affordance so it still reads as clickable. */
.top-stats .top-stat-button{width:100%;text-align:left;font:inherit;color:inherit;cursor:pointer;transition:border-color .12s ease}
.top-stats .top-stat-button:hover,.top-stats .top-stat-button:focus-visible{border-color:var(--green)}
.top-stats .top-stat-button:focus-visible{outline:2px solid var(--green);outline-offset:2px}
/* Vägda/Inköp status tint (set by render() in app.js). Both use the same
   green-when-done/red-when-not framing -- Vägda: green once everything's
   weighed, red while something isn't. Inköp: green while the shopping
   list is empty, red as soon as there's something to buy. */
.top-stats article.stat-alert,.top-stats .top-stat-button.stat-alert{border-color:var(--danger-line);background-color:var(--danger-bg)}
.top-stats article.stat-alert strong,.top-stats .top-stat-button.stat-alert strong{color:var(--danger-text)}
.top-stats article.stat-good,.top-stats .top-stat-button.stat-good{border-color:var(--status-under-line);background-color:color-mix(in srgb, var(--green) 14%, var(--card))}
.target-card div{display:flex;align-items:baseline;gap:4px;margin-top:2px}
.target-card input{width:70px;border:0;border-bottom:1px solid transparent;background:transparent;color:var(--text);padding:0;font-size:20px;font-weight:800}
.target-card input:hover,.target-card input:focus{outline:0;border-bottom-color:var(--green)}
.target-card b{font-size:14px}
.target-card small{display:block;margin-top:3px;color:var(--muted);font-size:10px;white-space:nowrap}
/* Whole-card tint, not just the border -- under target is a flat subtle
   green, over target ramps from a light to a more saturated red the
   further over you are. The over intensity comes from --over-mix, a
   percentage app.js's renderTarget() sets per-render (see there); it's a
   custom property rather than a class so it's a smooth gradient instead
   of a few fixed steps. color-mix() blends against --card so it already
   adapts to the light/dark theme with no extra work. */
/* .status-card is shared by the editable Målvikt box and the plain
   read-only Vikt-kvar box next to it -- both need the same over/under
   tinting, only Målvikt additionally needs the input/label/small layout
   below (.target-card). --over-mix is set per-element by
   renderTarget() in app.js, so the two boxes tint independently even
   though they're driven by the same underlying difference value. */
.status-card.over{border-color:var(--status-over-line);background-color:color-mix(in srgb, var(--status-over-text) var(--over-mix, 14%), var(--card))}
.status-card.over small{color:var(--status-over-text)}
.status-card.under{border-color:var(--status-under-line);background-color:color-mix(in srgb, var(--green) 14%, var(--card))}
.status-card.under small{color:var(--green)}
.toolbar{display:grid;grid-template-columns:minmax(180px,1fr) 190px 130px;gap:10px;margin-bottom:16px}
.toolbar input,.toolbar select,.table-wrap input,.table-wrap select{width:100%;border:1px solid var(--line);border-radius:8px;background:var(--well);color:var(--text);padding:9px}
.days-control{display:grid;grid-template-columns:1fr 48px;align-items:center;gap:7px;border:1px solid var(--line);border-radius:8px;background:var(--well);padding:0 8px;color:var(--muted);font-size:11px;text-transform:uppercase}
.days-control input{border:0;padding:8px 2px;text-align:center}
.add-bottom{width:100%;margin-top:12px}
.packing-workspace{display:grid;grid-template-columns:minmax(0,1fr);align-items:start}
.packing-main{min-width:0}
.insights-grid{position:sticky;top:14px;display:grid;grid-template-columns:1fr;gap:14px;margin:0}
.sidebar-insights{position:static;margin-top:18px}
.sidebar-insights .insight-card{padding:14px}
.sidebar-insights .forecast-chart{height:105px}
.sidebar-insights .forecast-days{grid-template-columns:repeat(3,1fr)}
.insight-card{min-width:0;border:1px solid var(--line);border-radius:12px;background:var(--card);padding:18px}
.insight-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;margin-bottom:14px}
.insight-heading .eyebrow{margin-bottom:6px}.insight-heading h3{margin:0;font-size:16px}
.insight-heading label{display:flex;align-items:center;gap:7px;color:var(--muted);font-size:11px;text-transform:uppercase}
.insight-heading input{width:58px;border:1px solid var(--line);border-radius:7px;background:var(--well);color:var(--text);padding:7px}
.clear-filter{border:0;background:transparent;color:var(--green);font-size:12px;white-space:nowrap}
.forecast-summary{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-bottom:10px}
.forecast-summary div{border:1px solid var(--line);border-radius:8px;background:var(--card);padding:8px}
.forecast-summary span,.forecast-days span{display:block;color:var(--muted);font-size:9px;text-transform:uppercase}
.forecast-summary strong{display:block;margin-top:3px;font-size:13px}
.forecast-chart{height:125px;border-bottom:1px solid var(--line);background:linear-gradient(180deg,rgba(154,230,145,.04),transparent)}
.forecast-chart svg{display:block;width:100%;height:100%;overflow:visible}.forecast-area{fill:rgba(154,230,145,.1)}
.forecast-line{fill:none;stroke:var(--green);stroke-width:3;stroke-linecap:round;stroke-linejoin:round}.forecast-dot{fill:var(--bg);stroke:var(--green);stroke-width:3}
.forecast-days{display:grid;grid-template-columns:repeat(auto-fit,minmax(78px,1fr));gap:5px;margin-top:10px}
.forecast-days div{border:1px solid var(--line);border-radius:7px;padding:6px 7px;background:var(--card)}
.forecast-days div.first,.forecast-days div.last{border-color:var(--accent-line);background:var(--accent-soft)}
.forecast-days strong{display:block;margin-top:2px;font-size:11px;white-space:nowrap}
.forecast-caption{margin:12px 0 0;color:var(--muted);font-size:12px;line-height:1.45}
.category-chart{display:grid;gap:7px}.category-bar{display:grid;grid-template-columns:minmax(75px,110px) minmax(55px,1fr) 64px;align-items:center;gap:9px;width:100%;border:1px solid transparent;border-radius:7px;background:transparent;color:var(--text);padding:5px;text-align:left}
.category-bar:hover,.category-bar.active{border-color:var(--line);background:var(--hover)}.category-bar span{overflow:hidden;text-overflow:ellipsis;font-size:12px}
.category-bar i{height:7px;border-radius:99px;background:var(--track);overflow:hidden}.category-bar b{display:block;height:100%;border-radius:inherit;background:var(--green)}
.category-bar strong{text-align:right;font-size:12px}.empty-insight{padding:45px 12px;color:var(--muted);font-size:12px;text-align:center}
.table-wrap{overflow-x:auto;border:1px solid var(--line);border-radius:12px}
table{width:100%;min-width:900px;border-collapse:collapse}
th,td{padding:10px 8px;border-bottom:1px solid var(--line);text-align:left;font-size:13px}
th{color:var(--muted);font-size:11px;font-weight:600;text-transform:uppercase}
th abbr{text-decoration:none;cursor:help}
.table-wrap th:first-child,.table-wrap td:first-child{position:sticky;left:0;z-index:2;min-width:236px;background:var(--card);box-shadow:1px 0 0 var(--line)}
.table-wrap th:first-child{z-index:3}
td:nth-child(5){text-align:center}td input[type=checkbox]{width:auto}
td input[type=checkbox]:disabled{cursor:not-allowed;opacity:.25}
/* Hidden by default (desktop already has a <th>Har</th> column header,
   so repeating "Har" inside every cell would just be clutter there) --
   the 700px breakpoint switches this back on for labels that only make
   sense once the table becomes mobile cards. */
.mobile-only-text{display:none}
/* flex, not grid -- flex items shrink together properly (with min-width:0,
   see below) instead of grid's "auto"/"1fr" tracks silently keeping a
   content-sized floor that can overflow the row on a narrow phone. */
.item-name-field{display:flex;align-items:center;gap:6px}
.item-name-field>input{flex:1 1 90px;min-width:0}
.item-name-field .item-actions,.item-name-field .delete-button{flex:0 0 auto}
/* ---- per-item hover actions (2026-07-31) -- Förbrukas/Bärs på
   kroppen/Favorit used to be table columns (Förbrukas still was, until
   this change; worn was removed entirely in an earlier commit, favorite
   never existed). Now a row of small toggle buttons that live inside the
   name cell but stay invisible until the row is hovered, matching the
   reference mockup Tor sent. They're real focusable <button>s the whole
   time (see actionToggle() in app.js) so Tab still reaches them and
   :focus-within reveals them for keyboard users -- opacity/pointer-events
   are the only things toggling, nothing is removed from the tab order. ---- */
.item-actions{display:flex;gap:3px}
/* Active flags (consumable/worn/favorite that are ON) always show, even
   with the mouse elsewhere -- that's the actual state of the item, not
   just a hover affordance. Only the *inactive* buttons hide themselves
   until the row is hovered or one of them gets keyboard focus, so an
   untouched row stays uncluttered but nothing you've already chosen ever
   disappears. */
.item-action{display:grid;place-items:center;width:22px;height:22px;border:1px solid var(--line);border-radius:6px;background:transparent;color:var(--muted);font-size:12px;font-weight:700;padding:0;line-height:1;opacity:0;pointer-events:none;transition:opacity .12s ease}
.item-action.active{opacity:1;pointer-events:auto}
tr:hover .item-action,.item-actions:focus-within .item-action{opacity:1;pointer-events:auto}
.item-action:hover{border-color:var(--green);color:var(--green)}
.item-action.active{border-color:var(--green);background:var(--accent-soft);color:var(--green)}
.item-action:disabled{opacity:.3;cursor:not-allowed}
.item-action:disabled:hover{border-color:var(--line);color:var(--muted)}
.item-action:focus-visible{outline:2px solid var(--green);outline-offset:1px}
.weight-field{display:grid;grid-template-columns:minmax(86px,1fr) auto;align-items:center;gap:7px}
.weighed-check{display:flex;align-items:center;gap:4px;color:var(--muted);font-size:11px;white-space:nowrap;cursor:pointer}
.weighed-check:has(input:checked){color:var(--green)}
/* Same footprint as .item-action (22x22, transparent, thin border) so the
   delete "x" reads as part of the same row of small icon buttons instead
   of a bigger, visually separate control -- only the red danger color
   keeps it distinguishable. Always visible (no hover-reveal opacity like
   .item-action) since removing an item is a deliberate, findable action,
   not a per-row flag you toggle in passing. */
.delete-button{display:grid;place-items:center;width:22px;height:22px;border:1px solid var(--danger-line);border-radius:6px;background:transparent;color:var(--danger-text);font-size:15px;font-weight:700;padding:0;line-height:1}
.delete-button:hover{border-color:var(--danger-line-hover);background:var(--danger-bg)}
.close-button{border:0;background:transparent;color:var(--danger-line-hover);font-size:23px}
.empty-list{padding:80px 20px;text-align:center}.empty-list>span{color:var(--green);font-size:36px}.empty-list h3{margin:14px 0 6px}.empty-list p{color:var(--muted)}
.empty-list.compact{padding:60px 20px}
.subview{min-height:520px}
.view-heading{display:flex;align-items:center;justify-content:space-between;gap:24px;margin-bottom:22px}
.view-heading h2{margin:0;font-family:Georgia,serif;font-size:34px;font-weight:500}
.view-heading p:not(.eyebrow){margin:8px 0 0;color:var(--muted)}
.shopping-list{display:grid;gap:8px}
.shopping-item{display:grid;grid-template-columns:minmax(170px,.8fr) minmax(240px,1.2fr) auto;align-items:center;gap:18px;border:1px solid var(--line);border-radius:10px;background:var(--card);padding:14px 16px}
.shopping-item strong,.shopping-item span{display:block}.shopping-item span{margin-top:4px;color:var(--muted);font-size:12px}
.shopping-item label{white-space:nowrap;color:var(--green);font-size:13px}.shopping-item input{margin-right:5px}
.shopping-note{width:100%;min-height:48px;resize:vertical;border:1px solid var(--line);border-radius:8px;background:var(--well);color:var(--text);padding:9px 10px;font:inherit;font-size:13px;line-height:1.35}
.shopping-note:focus{border-color:var(--green);outline:2px solid rgba(149,226,136,.16)}
.print-sheet{width:min(794px,100%);min-height:1123px;margin:auto;background:#fff;color:#182019;padding:56px 60px;box-shadow:0 20px 60px rgba(0,0,0,.25)}
.print-sheet header{margin-bottom:24px}.print-sheet header>p{margin:0 0 8px;color:#52705e;font-size:10px;font-weight:800;letter-spacing:.18em}
.print-sheet h1{margin:0;font-family:Georgia,serif;font-size:32px}.print-summary{display:flex;flex-wrap:wrap;gap:8px 20px;margin-top:14px;font-size:12px}
.print-table{min-width:0;color:#182019}.print-table th,.print-table td{border-color:#cfd5d0;padding:8px 6px;font-size:11px}.print-table th{color:#526158}
.print-table th:first-child,.print-table td:first-child{width:24px}.print-empty{padding:50px;text-align:center;color:#66736b}
/* ---- density setting (dropdown, see .dropdown-field above) -- toggled
   via app.js adding/removing this class on .planner itself, so it scopes
   to one planner instance's own row spacing without touching anything
   outside it. Comfortable (the pre-existing spacing) needs no class. ---- */
.planner.density-compact th,.planner.density-compact td{padding:5px 8px}
.planner.density-compact .top-stats article,.planner.density-compact .top-stats .top-stat-button{padding:8px 12px}
.planner.density-compact .top-stats strong{font-size:17px}
.planner.density-compact .insight-card{padding:12px}
.planner.density-compact .shopping-item{padding:9px 12px}

.private-main{width:min(1500px,calc(100% - 40px));margin:24px auto 60px}
.modal-backdrop{position:fixed;inset:0;z-index:20;display:grid;place-items:center;padding:20px;background:rgba(2,8,5,.78);backdrop-filter:blur(8px)}
.login-card{position:relative;width:min(430px,100%);border:1px solid var(--line);border-radius:18px;background:var(--panel);padding:30px;box-shadow:0 30px 100px #000}
.login-card h2{margin:0 0 24px;font-family:Georgia,serif;font-size:30px;font-weight:500}
.login-card form{display:grid;gap:8px}.login-card label{color:var(--muted);font-size:12px}
.login-card input{width:100%;margin-bottom:8px;border:1px solid var(--line);border-radius:8px;background:var(--well);color:var(--text);padding:11px}
.login-card .primary-button,.login-card .secondary-button{width:100%;margin-top:6px}
.auth-divider{display:flex;align-items:center;gap:10px;margin:16px 0 10px;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.12em}
.auth-divider::before,.auth-divider::after{content:"";height:1px;flex:1;background:var(--line)}
.close-button{position:absolute;right:14px;top:10px}.form-message{min-height:20px;margin-bottom:0;color:var(--warn);font-size:13px;line-height:1.4}
.planner-modal-backdrop{position:fixed;inset:0;z-index:30;display:grid;place-items:center;padding:20px;background:rgba(2,8,5,.78);backdrop-filter:blur(8px)}
.new-list-card{width:min(430px,100%);border:1px solid var(--line);border-radius:18px;background:var(--panel);padding:28px;box-shadow:0 30px 100px #000}
.new-list-card h2{margin:0 0 22px;font-family:Georgia,serif;font-size:30px;font-weight:500}
.new-list-card form{display:grid;gap:8px}.new-list-card label{color:var(--muted);font-size:12px}
.new-list-card input{width:100%;margin-bottom:8px;border:1px solid var(--line);border-radius:8px;background:var(--well);color:var(--text);padding:11px}
.new-list-actions{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:4px}
@media(max-width:1200px){
  .planner{grid-template-columns:300px minmax(0,1fr)}
}
@media(max-width:700px){
  .shopping-item{grid-template-columns:1fr auto}
  .shopping-note{grid-column:1/-1;grid-row:2}
  /* Packing table -> stacked cards (2026-07-31). A real <table> with 5
     columns (name+actions, category, weight/weighed, quantity, owned)
     doesn't fit a phone's width -- forcing horizontal scroll meant Vikt,
     Antal and Har were permanently off-screen unless you scrolled
     sideways per row. Standard accessible responsive-table technique:
     keep the real <table>/<th>/<td> markup and semantics (screen readers
     still get real table relationships), just make every row a block
     card and visually hide the header row -- each cell (except the name,
     which is self-evident) gets a small pseudo-heading from the
     data-label attribute itemRow() in app.js already sets on it. */
  .table-wrap{overflow-x:visible;border:0;border-radius:0}
  table{width:100%;min-width:0}
  thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}
  /* Card layout is flex-wrap, not CSS Grid (2026-08-01) -- grid tracks
     ("auto"/plain "1fr") keep an implicit content-sized floor and just
     overflow their box when there isn't room for it; a real-phone
     screenshot caught exactly that (name + F/B/star/x + Har overlapping).
     flex-wrap can't do that -- an item that doesn't fit wraps to a new
     line instead, so overlap is impossible by construction.
     Two explicit rows, per Tor: row 1 is Kategori + Antal + Vikt (Vägd
     rides along inside the Vikt cell, see .weight-field), row 2 is Pryl
     (name, with its F/B/star/x actions riding along the same way) + Har.
     Flexbox has no native "hard break here" between two same-level
     items, so a zero-size ::after pseudo-element with flex-basis:100%
     sits between the two groups (order:4, between vikt's 3 and name's
     5) -- a standard trick: a 100%-wide flex item can't share a line
     with anything, which forces everything ordered after it onto a new
     line, without needing an extra real DOM element. */
  tbody tr{
    display:flex;flex-wrap:wrap;align-items:flex-start;column-gap:8px;row-gap:6px;
    margin-bottom:10px;border:1px solid var(--line);border-radius:12px;padding:10px 10px;background:var(--card);
  }
  tbody tr::after{content:"";order:4;flex-basis:100%}
  td{border-bottom:0;padding:0;min-width:0}
  /* namn -- flex-grow:0 now (was 1) so it hugs its own content instead
     of stretching to fill row 2, which used to shove Har all the way to
     the row's far right edge. With no grow, Har (order:6, right after)
     lands snug next to the delete button instead, per Tor. */
  td:nth-child(1){flex:0 1 auto;order:5} /* namn */
  .mobile-only-text{display:inline}
  /* Row 1's three fields split proportionally now (Tor: "40, 25, 25, 10"
     of Kategori/Antal/Vikt/Vägd) instead of Kategori taking whatever was
     left over after Antal+Vikt's fixed pixel widths -- flex-grow ratios
     with flex-basis:0 divide 100% of the row between them (Vikt's 25 and
     Vägd's 10 both live inside td:nth-child(3), split again below via
     .weight-field's own grid). Kategori getting a guaranteed 40% (not
     "whatever's left") is what actually fixes long names getting
     ellipsized down to nothing, like "Bränsle"/"Elektronik" did with the
     previous width:auto/max-width:100% approach. */
  td:nth-child(2){flex:40 0 0;order:1} /* kategori */
  td:nth-child(3){flex:35 0 0;order:3} /* vikt (25) + vägd (10) */
  td:nth-child(4){flex:25 0 0;order:2} /* antal */
  td:nth-child(5){flex:0 0 auto;order:6} /* har */
  /* Name used to be first/top with a border-bottom separating it from the
     fields below; now it's on row 2 (order:5, see tbody tr above), so
     the same divider moves to border-top instead, still separating name
     from the field group above it. */
  .table-wrap th:first-child,.table-wrap td:first-child{position:static;min-width:0;background:transparent;box-shadow:none;padding-top:5px;border-top:1px solid var(--line)}
  /* [data-label], not td[data-label] -- Vikt and Vägd now each carry
     their own data-label on a wrapper *inside* weightCell (.weight-
     input-wrap / .vagd-wrap, see itemRow()) instead of one shared
     data-label on the td covering both. Two independent ::before
     headers, each sitting directly above its own element, is what
     actually puts "VÄGD" on the exact same header line as Kategori/
     Antal/Vikt -- the previous column-reverse-inside-one-shared-cell
     approach could only ever approximate that, since Vägd's checkbox
     lived one nesting level deeper than the other three fields' own
     tds. */
  [data-label]::before{content:attr(data-label);display:block;margin-bottom:3px;color:var(--muted);font-size:10px;text-transform:uppercase;letter-spacing:.05em}
  /* Har went back to an inline "Har" label next to its checkbox (see
     itemRow()'s .mobile-only-text span) instead of this pseudo-heading
     -- showing both would be the same word twice again. */
  td[data-label="Har"]::before{display:none}
  /* Antal/Kategori/Vikt fill whatever width their td's flex-grow ratio
     (above) actually gave them, instead of a guessed fixed pixel width
     -- width:100% always matches the real container, so it can't repeat
     the earlier bug where a select's own auto-sizing (by its widest
     option, ignoring the td it sat in) bled into the next cell. */
  td[data-label="Antal"] input{width:100%}
  .weight-input-wrap input{width:100%;min-width:0}
  td[data-label="Kategori"] select{width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis}
  /* Vikt (25) and Vägd (10) split td:nth-child(3)'s 35% share 5:2
     (=25:10) via the same flex-grow-ratio approach as the outer row,
     so the split holds regardless of how wide that td ends up being.
     Overrides the desktop .weight-field's minmax(86px,1fr) column.
     align-items:start (not the desktop default center) since both
     columns now build their own label-above-control stack and should
     line up at the top, like Kategori/Antal do. */
  .weight-field{grid-template-columns:5fr 2fr;column-gap:5px;align-items:start}
  .vagd-wrap{min-width:0}
  /* The inline "Vägd" text next to the checkbox is desktop-only now --
     on mobile, .vagd-wrap's own "VÄGD" pseudo-heading (above) says it
     instead, so showing this too would repeat it. */
  .weighed-check-label{display:none}
  td:nth-child(5){display:flex;align-items:center;text-align:left}
}
/* Hover-revealed item-action buttons (Förbrukas/Bärs på kroppen/Favorit,
   see .item-action) rely on tr:hover, which touch input never triggers --
   without this, an inactive flag could only ever be seen/unset on a
   phone, never newly set, since there's no hover to reveal the button in
   the first place. (hover:none) targets touch/no-hover input specifically
   rather than a screen-width breakpoint, so it also covers touch
   laptops/desktops regardless of window size. */
@media(hover:none){
  .item-action{opacity:1;pointer-events:auto}
}
@media(max-width:800px){
  .hero{grid-template-columns:1fr;gap:48px;min-height:0;padding:70px 0}.hero-card{max-width:520px}
  .section-heading{display:block}.section-heading>p{margin-top:12px}
  /* Mobile re-orders the whole planner into one flow instead of stacking
     .planner-sidebar's entire contents above .planner-content's (2026-07-31)
     -- that used to bury the actual item table under the list name, nav,
     and both insight charts, several screens of scrolling before you
     reached anything editable. display:contents lifts each wrapper's own
     children up to be direct flex children of .planner, so every one of
     them can be reordered against each other with a single `order` value
     regardless of which original wrapper it came from. New order: list
     name -> nav (sticky, so it's reachable while scrolling) -> save
     status -> quick stats -> the actual table -> the two insight charts,
     which move from second to last. */
  .planner{display:flex;flex-direction:column;padding:20px 14px 14px}
  .planner-sidebar,.planner-content{display:contents}
  .planner-sidebar>div:first-child{order:1}
  .planner-nav{order:2;position:sticky;top:0;z-index:5;background:var(--card);padding:10px 0 8px;margin:0 0 14px;grid-template-columns:repeat(3,1fr)}
  .planner-nav button{justify-content:center;gap:6px;text-align:center}
  .save-state-top{order:3}
  .top-stats{order:4;grid-template-columns:repeat(3,1fr);margin-bottom:18px}
  [data-view="packing"],[data-view="shopping"],[data-view="print"]{order:5}
  .toolbar{grid-template-columns:1fr 1fr}.toolbar .primary-button{grid-column:1/-1}
  .sidebar-insights{order:6;margin-top:24px}
  /* Redundant with .save-state-top once everything's reordered -- that's
     already right under the nav, no need for a second "Sparad ✓" further
     down in the new flow. */
  .planner-sidebar>p.save-state{display:none}
  .view-heading{align-items:flex-start}.print-sheet{min-height:0;padding:32px 24px}
}
@media(max-width:480px){
  .site-header,.app-header,.hero,.planner-section,.private-main{width:calc(100% - 24px)}
  .hero h1{font-size:48px}.lead{font-size:17px}.hero-card>strong{font-size:42px}
  .planner-section,.private-main{width:100%;margin-bottom:0}.section-heading{padding:0 12px}
  .planner{border-left:0;border-right:0;border-radius:0;padding:20px 10px 14px}
  .top-stats{grid-template-columns:1fr 1fr;gap:8px}.top-stats article,.top-stats .top-stat-button{padding:10px 12px}
  /* Målvikt used to force itself to grid-column:1/-1 (full row width,
     alone) at this breakpoint -- Tor wanted it the same size as Vikt kvar
     and sharing a row instead, so it's a normal grid item now like every
     other stat box. The status line under it ("X kg under mål") is too
     long to fit on one line at half-width, so let it wrap instead of
     overflowing (it had white-space:nowrap for the wider two-column
     layouts, where it fits fine on one line). */
  .target-card small{white-space:normal;line-height:1.3}
  .dropdown-panel{width:min(280px,calc(100vw - 24px))}
  .planner-nav button{padding:9px 5px;font-size:12px}.view-heading{display:block}.view-heading .primary-button{width:100%;margin-top:14px}
  .shopping-item{align-items:flex-start}.print-sheet{padding:24px 14px}.print-summary{display:grid;grid-template-columns:1fr 1fr}
}
@page{size:A4 portrait;margin:12mm}
@media print{
  body{background:#fff}
  body *{visibility:hidden}
  [data-view="print"]:not([hidden]),[data-view="print"]:not([hidden]) *{visibility:visible}
  [data-view="print"]:not([hidden]){position:absolute;inset:0;display:block!important}
  .print-sheet{width:auto;min-height:0;margin:0;padding:0;box-shadow:none}
  /* visibility:hidden alone leaves layout space behind and doesn't
     reliably suppress box-shadow/backdrop-filter in every print engine,
     which can show up as a stray colored/shadowed box below the actual
     print sheet ("konstigt fält" -- reported 2026-07-31). These are the
     elements with a background, shadow or blur that could leak through:
     force them fully out of the render tree instead of just invisible. */
  .site-header,.app-header,.planner-sidebar,.top-stats,.save-state-top,
  .toolbar,[data-view="packing"],[data-view="shopping"],
  .modal-backdrop,.planner-modal-backdrop{display:none!important}
  .no-print{display:none!important}
  .print-table{page-break-inside:auto}.print-table tr{page-break-inside:avoid}
}

/* ---- light theme (2026-07-31, "Mörkt läge" toggle in settings dropdown)
   Every surface/text color in this file was consolidated into the tokens
   defined at the top of :root specifically so this one block could redefine
   the whole app's palette. app.js's applyTheme() toggles this class on
   <html> based on prefs.theme; a tiny inline script in index.html's <head>
   applies it before first paint too, straight from localStorage, so there's
   no dark-then-light flash on reload. .print-sheet is intentionally left
   out -- it's always rendered white-on-black regardless of theme, since
   that's what gets printed on paper either way. ---- */
html.theme-light{
  --bg:var(--paper);--panel:#ffffff;--card:#ffffff;--well:#eef2ec;
  --hover:#e4efe8;--accent-soft:#e2f1e5;--accent-line:#7fbf8f;
  --line:#dbe1d7;--text:var(--ink);--muted:#5b6b60;--lead:#46564c;
  --green:#2f8f45;--on-accent:#f4fbf5;--warn:#8a6a1f;
  --danger-bg:#fbe4dc;--danger-line:#e4b2a0;--danger-text:#a9503a;
  --danger-bg-hover:#f6d2c4;--danger-line-hover:#c96b4d;
  --status-over-line:#e2a394;--status-over-text:#b3543c;--status-under-line:#8fd3a0;
  --track:#e2ece2;
}
html.theme-light .login-card,html.theme-light .new-list-card,html.theme-light .dropdown-panel{box-shadow:0 20px 60px rgba(30,40,34,.14)}
html.theme-light .planner,html.theme-light .hero-card{box-shadow:0 20px 60px rgba(30,40,34,.1)}
