{ self, inputs, ... }: {

  # Lenovo Chromebook Duet 3 (`lenovo-wormdingler`) on Mobile NixOS.
  # Full V2 stack: mobile-nixos device + Niri/Hyprland/DMS, DankGreeter, wvkbd, IIO sensors,
  # touchscreen calibration + resume-rebind, attic cache, sops, and the standard user catalog.
  # Host-only quirks live in `_private/touch-tablet.nix` and `_private/platform.nix`.
  flake.nixosModules.ideapadConfiguration =
    {
      self,
      config,
      lib,
      pkgs,
      ...
    }:
    {
      imports = [
        # Mobile NixOS device + family + depthcharge system-type.
        (import "${inputs.mobile-nixos}/lib/configuration.nix" {
          device = "lenovo-wormdingler";
        })

        self.nixosModules.ideapadHardware

        inputs.home-manager.nixosModules.home-manager
        inputs.sops-nix.nixosModules.sops

        self.nixosModules.system
        self.nixosModules.desktop
        self.nixosModules.users

        self.nixosModules."client-services"

        # Host-only: IIO + touchscreen calibration + per-compositor tablet/autorotate helpers.
        ./_private/touch-tablet.nix

        # Host-only: cpufreq, lid/power-button policy, upower thresholds.
        ./_private/platform.nix
      ];

      # ─────────────────────── Sops ───────────────────────
      # `host_ideapad` recipient in `.sops.yaml` derives from the new ed25519 host key (post-reflash).
      sops = {
        defaultSopsFile = ../../../secrets/secrets.yaml;
        defaultSopsFormat = "yaml";
        age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
      };

      sops.secrets."users/olivier/hashedPassword".neededForUsers = true;
      sops.secrets."caching/attic/token" = {
        owner = "olivier";
        group = "users";
        mode = "0400";
      };
      sops.secrets."swiftshare/API_KEY" = {
        owner = "olivier";
        group = "users";
        mode = "0400";
      };

      # ─────────────────────── Mobile NixOS / firmware ───────────────────────
      # mruby's test-suite breaks on aarch64 in the Nix sandbox; the overlay strips checks and
      # rebuilds Mobile NixOS' script-loader against the patched mruby.
      chiasson.system.ideapadMrubyOverlay.enable = true;

      # Wi-Fi modem (qcom-wcn3990) + Bluetooth (QCA crnv32) need binary blobs.
      nixpkgs.config.allowUnfreePredicate =
        pkg: builtins.elem (lib.getName pkg) [
          "chromeos-sc7180-unredistributable-firmware"
          "chromeos-sc7180-unredistributable-firmware-zstd"
        ];
      hardware.firmware = [ pkgs.chromeos-sc7180-unredistributable-firmware ];
      hardware.enableRedistributableFirmware = true;

      # ─────────────────────── Attic (substitution + push + CLI token) ───────
      chiasson.system.caching.attic = {
        enable = true;
        cacheName = "nixos-new";
        endpoint = "http://192.168.2.238:8080/";
        publicKey = "nixos-new:8NySIcT0HP7KvGQKgBRWoWESxxRA8BVYo8S85UNpNX0=";
        tokenFile = config.sops.secrets."caching/attic/token".path;
        push.enable = true;
        userCli.enable = true;
      };

      # ─────────────────────── System bits ───────────────────────
      chiasson.system = {
        audio.enable = true;
        networking = {
          hostName = "ideapad";
          networkManager = {
            enable = true;
            unmanaged = [ ];
          };
          wifi.tools.enabled = true;
        };
        extraPackages = with pkgs; [
          gitMinimal
          sops
          ssh-to-age
        ];
      };

      # ─────────────────────── Desktop ───────────────────────
      # Both compositors are enabled — DankGreeter picks at login, V2 default is Niri.
      # Per-session tablet-mode / autorotate daemons live in `_private/touch-tablet.nix`.
      chiasson.desktop = {
        niri.enable = true;
        hyprland.enable = true;

        defaultSession = "niri";
        shell = "dms";
        shells.dms = {
          enableWvkbdToggle = true;
          enableRbwLockToggle = true;
          # Cross-build on the 14900k via binfmt and push back over LAN — much faster than
          # rebuilding aarch64 closure on the Snapdragon. Mirrors the old NixOS-New flow:
          # ssh out to nixdesk, run nixos-rebuild --target-host pointing back at us.
          rebuildCommand = [
            "bash"
            "-lc"
            ''
              ssh -t olivier@nixdesk \
                "nixos-rebuild switch --flake path:/home/olivier/NixOS-V2#ideapad --target-host olivier@ideapad --sudo --ask-sudo-password 2>&1"
            ''
          ];
        };

      };

      # ─────────────────────── Users / HM ───────────────────────
      chiasson.users.enabled = [ "olivier" ];

      # Touch-friendly application set, mirroring uConsole's selection (no heavy IDEs / gaming).
      chiasson.users.extraModules.olivier = [
        self.homeManagerModules.wisdomFilebrowsersDolphin
        self.homeManagerModules.wisdomTerminalsKitty
        self.homeManagerModules.wisdomBrowsersZen
        self.homeManagerModules.wisdomEditorsKate
        self.homeManagerModules.wisdomEditorsCursor
        self.homeManagerModules.wisdomShellFish
        self.homeManagerModules.wisdomShellOhMyPosh
        self.homeManagerModules.wisdomAppsSpotify
        self.homeManagerModules.wisdomAppsLocalsend
        self.homeManagerModules.wisdomDesktopScreenshot
        {
          chiasson.home = {
            shell = {
              fish.enable = true;
              ohMyPosh.enable = true;
            };
            terminals.kitty.enable = true;
            filebrowsers.dolphin.enable = true;
            browsers.zen.enable = true;
            editors.kate.enable = true;
            editors.cursor.enable = true;
            apps.spotify.enable = true;
            apps.localsend.enable = true;
            desktop = {
              screenshot = {
                enable = true;
                swiftshareApiKeyFile = "/run/secrets/swiftshare/API_KEY"; #TODO[epic=sops] redo this by passing sops file output directly
              };
            };
          };
        }
        # Tablet-class apps: kept inline rather than promoting to wisdom modules — these aren't
        # part of the broader catalog (no use on uConsole / 14900k / servers) and adding a wisdom
        # module per single-host package would just be ceremony. If a second tablet host ever
        # appears, factor them out then.
        #
        # NOTE on cameras: no v4l2/libcamera GUI is installed. The Mobile NixOS kernel for
        # `lenovo-wormdingler` ships with `CONFIG_VIDEO_QCOM_CAMSS` disabled and no
        # `VIDEO_OV*`/`VIDEO_HI*` sensor drivers, so `/dev/video0`-`/dev/video1` only expose
        # the Qualcomm Venus codecs (h.264/h.265 enc/dec) and there is no camera source for
        # PipeWire / libcamera to pick up. See `_private/CAMERA-TODO.md` for the steps that
        # would (potentially) bring the front/rear cameras online — it's a kernel-rebuild +
        # device-tree + libcamera project, not a config tweak.
        (
          { pkgs, ... }:
          {
            home.packages = with pkgs; [
              # PDF viewer — fits the existing KDE app set (Dolphin + Kate).
              kdePackages.okular
              # ePub reader, GTK4, large touch targets.
              foliate
            ];
          }
        )
      ];

      system.stateVersion = "26.05";
    };
}
